YAZ  5.34.0
marcdisp.c
Go to the documentation of this file.
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) Index Data
3  * See the file LICENSE for details.
4  */
5 
11 #if HAVE_CONFIG_H
12 #include <config.h>
13 #endif
14 
15 #ifdef WIN32
16 #include <windows.h>
17 #endif
18 
19 #include <stdarg.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <yaz/marcdisp.h>
24 #include <yaz/wrbuf.h>
25 #include <yaz/yaz-util.h>
26 #include <yaz/nmem_xml.h>
27 #include <yaz/snprintf.h>
28 
29 #if YAZ_HAVE_XML2
30 #include <libxml/parser.h>
31 #include <libxml/tree.h>
32 #endif
33 
38 };
39 
42 {
47 };
48 
51  char *tag;
52  char *indicator;
54 };
55 
58  char *tag;
59  char *data;
60 };
61 
64  char *comment;
65 };
66 
68 struct yaz_marc_node {
70  union {
73  char *comment;
74  char *leader;
75  } u;
77 };
78 
81  char *code_data;
83 };
84 
86 struct yaz_marc_t_ {
90  int debug;
94  char subfield_str[8];
95  char endline_str[8];
96  char *leader_spec;
100 };
101 
103 {
104  yaz_marc_t mt = (yaz_marc_t) xmalloc(sizeof(*mt));
106  mt->debug = 0;
107  mt->write_using_libxml2 = 0;
109  mt->m_wr = wrbuf_alloc();
110  mt->iconv_cd = 0;
111  mt->leader_spec = 0;
112  strcpy(mt->subfield_str, " $");
113  strcpy(mt->endline_str, "\n");
114 
115  mt->nmem = nmem_create();
116  yaz_marc_reset(mt);
117  return mt;
118 }
119 
121 {
122  if (!mt)
123  return ;
124  nmem_destroy(mt->nmem);
125  wrbuf_destroy(mt->m_wr);
126  xfree(mt->leader_spec);
127  xfree(mt);
128 }
129 
131 {
132  return mt->nmem;
133 }
134 
135 static void marc_iconv_reset(yaz_marc_t mt, WRBUF wr)
136 {
137  wrbuf_iconv_reset(wr, mt->iconv_cd);
138 }
139 
140 static int marc_exec_leader(const char *leader_spec, char *leader,
141  size_t size);
142 #if YAZ_HAVE_XML2
143 static int yaz_marc_write_xml_turbo_xml(yaz_marc_t mt, xmlNode **root_ptr,
144  const char *ns,
145  const char *format,
146  const char *type);
147 #endif
148 
150 {
151  struct yaz_marc_node *n = (struct yaz_marc_node *)
152  nmem_malloc(mt->nmem, sizeof(*n));
153  n->next = 0;
154  *mt->nodes_pp = n;
155  mt->nodes_pp = &n->next;
156  return n;
157 }
158 
159 #if YAZ_HAVE_XML2
160 void yaz_marc_add_controlfield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
161  const xmlNode *ptr_data)
162 {
163  struct yaz_marc_node *n = yaz_marc_add_node(mt);
165  n->u.controlfield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
166  n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
167 }
168 
170  const xmlNode *ptr_data)
171 {
172  struct yaz_marc_node *n = yaz_marc_add_node(mt);
174  n->u.controlfield.tag = tag;
175  n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
176 }
177 
178 #endif
179 
180 
182 {
183  struct yaz_marc_node *n = yaz_marc_add_node(mt);
184  n->which = YAZ_MARC_COMMENT;
185  n->u.comment = nmem_strdup(mt->nmem, comment);
186 }
187 
188 void yaz_marc_cprintf(yaz_marc_t mt, const char *fmt, ...)
189 {
190  va_list ap;
191  char buf[200];
192 
193  va_start(ap, fmt);
194  yaz_vsnprintf(buf, sizeof(buf)-1, fmt, ap);
195  yaz_marc_add_comment(mt, buf);
196  va_end (ap);
197 }
198 
200 {
201  return mt->debug;
202 }
203 
204 void yaz_marc_add_leader(yaz_marc_t mt, const char *leader, size_t leader_len)
205 {
206  struct yaz_marc_node *n = yaz_marc_add_node(mt);
207  n->which = YAZ_MARC_LEADER;
208  n->u.leader = nmem_strdupn(mt->nmem, leader, leader_len);
209  marc_exec_leader(mt->leader_spec, n->u.leader, leader_len);
210 }
211 
212 void yaz_marc_add_controlfield(yaz_marc_t mt, const char *tag,
213  const char *data, size_t data_len)
214 {
215  struct yaz_marc_node *n = yaz_marc_add_node(mt);
217  n->u.controlfield.tag = nmem_strdup(mt->nmem, tag);
218  n->u.controlfield.data = nmem_strdupn(mt->nmem, data, data_len);
219  if (mt->debug)
220  {
221  size_t i;
222  char msg[80];
223 
224  sprintf(msg, "controlfield:");
225  for (i = 0; i < 16 && i < data_len; i++)
226  sprintf(msg + strlen(msg), " %02X", data[i] & 0xff);
227  if (i < data_len)
228  sprintf(msg + strlen(msg), " ..");
229  yaz_marc_add_comment(mt, msg);
230  }
231 }
232 
233 void yaz_marc_add_datafield(yaz_marc_t mt, const char *tag,
234  const char *indicator, size_t indicator_len)
235 {
236  struct yaz_marc_node *n = yaz_marc_add_node(mt);
238  n->u.datafield.tag = nmem_strdup(mt->nmem, tag);
239  n->u.datafield.indicator =
240  nmem_strdupn(mt->nmem, indicator, indicator_len);
241  n->u.datafield.subfields = 0;
242 
243  /* make subfield_pp the current (last one) */
244  mt->subfield_pp = &n->u.datafield.subfields;
245 }
246 
254  yaz_marc_t mt, WRBUF buffer,
255  const char *attribute_name, char *code_data, size_t code_len)
256 {
257  /* TODO Map special codes to something possible for XML ELEMENT names */
258 
259  int encode = 0;
260  size_t index = 0;
261  int success = 0;
262  for (index = 0; index < code_len; index++)
263  {
264  if (!((code_data[index] >= '0' && code_data[index] <= '9') ||
265  (code_data[index] >= 'a' && code_data[index] <= 'z') ||
266  (code_data[index] >= 'A' && code_data[index] <= 'Z')))
267  encode = 1;
268  }
269  /* Add as attribute */
270  if (encode && attribute_name)
271  wrbuf_printf(buffer, " %s=\"", attribute_name);
272 
273  if (!encode || attribute_name)
274  wrbuf_iconv_write_cdata(buffer, mt->iconv_cd, code_data, code_len);
275  else
276  success = -1;
277 
278  if (encode && attribute_name)
279  wrbuf_printf(buffer, "\""); /* return error if we couldn't handle it.*/
280  return success;
281 }
282 
283 #if YAZ_HAVE_XML2
284 void yaz_marc_add_datafield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
285  const char *indicator, size_t indicator_len)
286 {
287  struct yaz_marc_node *n = yaz_marc_add_node(mt);
289  n->u.datafield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
290  n->u.datafield.indicator = nmem_strdup(mt->nmem, indicator);
291  n->u.datafield.subfields = 0;
292 
293  /* make subfield_pp the current (last one) */
294  mt->subfield_pp = &n->u.datafield.subfields;
295 }
296 
297 void yaz_marc_add_datafield_xml2(yaz_marc_t mt, char *tag_value, char *indicators)
298 {
299  struct yaz_marc_node *n = yaz_marc_add_node(mt);
301  n->u.datafield.tag = tag_value;
302  n->u.datafield.indicator = indicators;
303  n->u.datafield.subfields = 0;
304 
305  /* make subfield_pp the current (last one) */
306  mt->subfield_pp = &n->u.datafield.subfields;
307 }
308 
309 void yaz_marc_datafield_set_indicators(struct yaz_marc_node *n, char *indicator)
310 {
311  n->u.datafield.indicator = indicator;
312 }
313 
314 #endif
315 
317  const char *code_data, size_t code_data_len)
318 {
319  if (mt->debug)
320  {
321  size_t i;
322  char msg[80];
323 
324  sprintf(msg, "subfield:");
325  for (i = 0; i < 16 && i < code_data_len; i++)
326  sprintf(msg + strlen(msg), " %02X", code_data[i] & 0xff);
327  if (i < code_data_len)
328  sprintf(msg + strlen(msg), " ..");
329  yaz_marc_add_comment(mt, msg);
330  }
331 
332  if (mt->subfield_pp)
333  {
334  struct yaz_marc_subfield *n = (struct yaz_marc_subfield *)
335  nmem_malloc(mt->nmem, sizeof(*n));
336  n->code_data = nmem_strdupn(mt->nmem, code_data, code_data_len);
337  n->next = 0;
338  /* mark subfield_pp to point to this one, so we append here next */
339  *mt->subfield_pp = n;
340  mt->subfield_pp = &n->next;
341  }
342 }
343 
344 static void check_ascii(yaz_marc_t mt, char *leader, int offset,
345  int ch_default)
346 {
347  if (leader[offset] < ' ' || leader[offset] > 127)
348  {
349  yaz_marc_cprintf(mt,
350  "Leader character at offset %d is non-ASCII. "
351  "Setting value to '%c'", offset, ch_default);
352  leader[offset] = ch_default;
353  }
354 }
355 
356 void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c,
357  int *indicator_length,
358  int *identifier_length,
359  int *base_address,
360  int *length_data_entry,
361  int *length_starting,
362  int *length_implementation)
363 {
364  char leader[24];
365 
366  memcpy(leader, leader_c, 24);
367 
368  check_ascii(mt, leader, 5, 'a');
369  check_ascii(mt, leader, 6, 'a');
370  check_ascii(mt, leader, 7, 'a');
371  check_ascii(mt, leader, 8, '#');
372  check_ascii(mt, leader, 9, '#');
373  if (!atoi_n_check(leader+10, 1, indicator_length) || *indicator_length == 0)
374  {
375  yaz_marc_cprintf(mt, "Indicator length at offset 10 should"
376  " hold a number 1-9. Assuming 2");
377  leader[10] = '2';
378  *indicator_length = 2;
379  }
380  if (!atoi_n_check(leader+11, 1, identifier_length) || *identifier_length == 0)
381  {
382  yaz_marc_cprintf(mt, "Identifier length at offset 11 should "
383  " hold a number 1-9. Assuming 2");
384  leader[11] = '2';
385  *identifier_length = 2;
386  }
387  if (!atoi_n_check(leader+12, 5, base_address))
388  {
389  yaz_marc_cprintf(mt, "Base address at offsets 12..16 should"
390  " hold a number. Assuming 0");
391  *base_address = 0;
392  }
393  check_ascii(mt, leader, 17, '#');
394  check_ascii(mt, leader, 18, '#');
395  check_ascii(mt, leader, 19, '#');
396  if (!atoi_n_check(leader+20, 1, length_data_entry) ||
397  *length_data_entry < 3)
398  {
399  yaz_marc_cprintf(mt, "Length data entry at offset 20 should"
400  " hold a number 3-9. Assuming 4");
401  *length_data_entry = 4;
402  leader[20] = '4';
403  }
404  if (!atoi_n_check(leader+21, 1, length_starting) || *length_starting < 4)
405  {
406  yaz_marc_cprintf(mt, "Length starting at offset 21 should"
407  " hold a number 4-9. Assuming 5");
408  *length_starting = 5;
409  leader[21] = '5';
410  }
411  if (!atoi_n_check(leader+22, 1, length_implementation))
412  {
413  yaz_marc_cprintf(mt, "Length implementation at offset 22 should"
414  " hold a number. Assuming 0");
415  *length_implementation = 0;
416  leader[22] = '0';
417  }
418  check_ascii(mt, leader, 23, '0');
419 
420  if (mt->debug)
421  {
422  yaz_marc_cprintf(mt, "Indicator length %5d", *indicator_length);
423  yaz_marc_cprintf(mt, "Identifier length %5d", *identifier_length);
424  yaz_marc_cprintf(mt, "Base address %5d", *base_address);
425  yaz_marc_cprintf(mt, "Length data entry %5d", *length_data_entry);
426  yaz_marc_cprintf(mt, "Length starting %5d", *length_starting);
427  yaz_marc_cprintf(mt, "Length implementation %5d", *length_implementation);
428  }
429  yaz_marc_add_leader(mt, leader, 24);
430 }
431 
432 void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
433 {
434  strncpy(mt->subfield_str, s, sizeof(mt->subfield_str)-1);
435  mt->subfield_str[sizeof(mt->subfield_str)-1] = '\0';
436 }
437 
438 void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
439 {
440  strncpy(mt->endline_str, s, sizeof(mt->endline_str)-1);
441  mt->endline_str[sizeof(mt->endline_str)-1] = '\0';
442 }
443 
444 /* try to guess how many bytes the identifier really is! */
445 static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
446 {
447  if (mt->iconv_cd)
448  {
449  size_t i;
450  for (i = 1; i<5; i++)
451  {
452  char outbuf[12];
453  size_t outbytesleft = sizeof(outbuf);
454  char *outp = outbuf;
455  const char *inp = buf;
456 
457  size_t inbytesleft = i;
458  size_t r = yaz_iconv(mt->iconv_cd, (char**) &inp, &inbytesleft,
459  &outp, &outbytesleft);
460  yaz_iconv(mt->iconv_cd, 0, 0, &outp, &outbytesleft);
461  if (r != (size_t) (-1))
462  return i; /* got a complete sequence */
463  }
464  return 1; /* giving up */
465  }
466  else
467  {
468  int error = 0;
469  size_t no_read = 0;
470  (void) yaz_read_UTF8_char((const unsigned char *) buf, 4,
471  &no_read, &error);
472  if (error == 0 && no_read > 0)
473  return no_read;
474  }
475  return 1; /* we don't know */
476 }
477 
478 size_t yaz_marc_sizeof_char(yaz_marc_t mt, const char *buf)
479 {
480  return cdata_one_character(mt, buf);
481 }
482 
484 {
485  nmem_reset(mt->nmem);
486  mt->nodes = 0;
487  mt->nodes_pp = &mt->nodes;
488  mt->subfield_pp = 0;
489 }
490 
492 {
493  struct yaz_marc_node *n;
494  int identifier_length;
495  const char *leader = 0;
496 
497  for (n = mt->nodes; n; n = n->next)
498  if (n->which == YAZ_MARC_LEADER)
499  {
500  leader = n->u.leader;
501  break;
502  }
503 
504  if (!leader)
505  return -1;
506  if (!atoi_n_check(leader+11, 1, &identifier_length))
507  return -1;
508 
509  for (n = mt->nodes; n; n = n->next)
510  {
511  switch(n->which)
512  {
513  case YAZ_MARC_COMMENT:
514  wrbuf_iconv_write(wr, mt->iconv_cd,
515  n->u.comment, strlen(n->u.comment));
516  wrbuf_puts(wr, "\n");
517  break;
518  default:
519  break;
520  }
521  }
522  return 0;
523 }
524 
525 static size_t get_subfield_len(yaz_marc_t mt, const char *data,
526  int identifier_length)
527 {
528  /* if identifier length is 2 (most MARCs) or less (probably an error),
529  the code is a single character .. However we've
530  seen multibyte codes, so see how big it really is */
531  if (identifier_length > 2)
532  return identifier_length - 1;
533  else
534  return cdata_one_character(mt, data);
535 }
536 
538 {
539  struct yaz_marc_node *n;
540  int identifier_length;
541  const char *leader = 0;
542 
543  for (n = mt->nodes; n; n = n->next)
544  if (n->which == YAZ_MARC_LEADER)
545  {
546  leader = n->u.leader;
547  break;
548  }
549 
550  if (!leader)
551  return -1;
552  if (!atoi_n_check(leader+11, 1, &identifier_length))
553  return -1;
554 
555  for (n = mt->nodes; n; n = n->next)
556  {
557  struct yaz_marc_subfield *s;
558  switch(n->which)
559  {
560  case YAZ_MARC_DATAFIELD:
561  wrbuf_printf(wr, "%s %s", n->u.datafield.tag,
562  n->u.datafield.indicator);
563  for (s = n->u.datafield.subfields; s; s = s->next)
564  {
565  size_t using_code_len = get_subfield_len(mt, s->code_data,
566  identifier_length);
567 
568  wrbuf_puts (wr, mt->subfield_str);
570  using_code_len);
571  wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
572  wrbuf_iconv_puts(wr, mt->iconv_cd,
573  s->code_data + using_code_len);
574  marc_iconv_reset(mt, wr);
575  }
576  wrbuf_puts (wr, mt->endline_str);
577  break;
579  wrbuf_printf(wr, "%s", n->u.controlfield.tag);
580  wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
582  marc_iconv_reset(mt, wr);
583  wrbuf_puts (wr, mt->endline_str);
584  break;
585  case YAZ_MARC_COMMENT:
586  wrbuf_puts(wr, "(");
587  wrbuf_iconv_write(wr, mt->iconv_cd,
588  n->u.comment, strlen(n->u.comment));
589  marc_iconv_reset(mt, wr);
590  wrbuf_puts(wr, ")\n");
591  break;
592  case YAZ_MARC_LEADER:
593  wrbuf_printf(wr, "%s\n", n->u.leader);
594  }
595  }
596  wrbuf_puts(wr, "\n");
597  return 0;
598 }
599 
601 {
603  {
604  switch(mt->output_format)
605  {
606  case YAZ_MARC_MARCXML:
607  case YAZ_MARC_TURBOMARC:
608  wrbuf_printf(wr, "</collection>\n");
609  break;
610  case YAZ_MARC_XCHANGE:
611  wrbuf_printf(wr, "</collection>\n");
612  break;
613  }
614  }
615  return 0;
616 }
617 
619 {
621 }
622 
624 {
625  switch(mt->output_format)
626  {
627  case YAZ_MARC_LINE:
628  return yaz_marc_write_line(mt, wr);
629  case YAZ_MARC_MARCXML:
630  return yaz_marc_write_marcxml(mt, wr);
631  case YAZ_MARC_TURBOMARC:
632  return yaz_marc_write_turbomarc(mt, wr);
633  case YAZ_MARC_XCHANGE:
634  return yaz_marc_write_marcxchange(mt, wr, 0, 0); /* no format, type */
635  case YAZ_MARC_ISO2709:
636  return yaz_marc_write_iso2709(mt, wr);
637  case YAZ_MARC_CHECK:
638  return yaz_marc_write_check(mt, wr);
639  case YAZ_MARC_JSON:
640  return yaz_marc_write_json(mt, wr);
641  }
642  return -1;
643 }
644 
645 static const char *record_name[2] = { "record", "r"};
646 static const char *leader_name[2] = { "leader", "l"};
647 static const char *controlfield_name[2] = { "controlfield", "c"};
648 static const char *datafield_name[2] = { "datafield", "d"};
649 static const char *indicator_name[2] = { "ind", "i"};
650 static const char *subfield_name[2] = { "subfield", "s"};
651 
663  const char *ns,
664  const char *format,
665  const char *type,
666  int turbo)
667 {
668  struct yaz_marc_node *n;
669  int identifier_length;
670  const char *leader = 0;
671 
672  for (n = mt->nodes; n; n = n->next)
673  if (n->which == YAZ_MARC_LEADER)
674  {
675  leader = n->u.leader;
676  break;
677  }
678 
679  if (!leader)
680  return -1;
681  if (!atoi_n_check(leader+11, 1, &identifier_length))
682  return -1;
683 
684  if (mt->enable_collection != no_collection)
685  {
687  {
688  wrbuf_printf(wr, "<collection xmlns=\"%s\">\n", ns);
690  }
691  wrbuf_printf(wr, "<%s", record_name[turbo]);
692  }
693  else
694  {
695  wrbuf_printf(wr, "<%s xmlns=\"%s\"", record_name[turbo], ns);
696  }
697  if (format)
698  wrbuf_printf(wr, " format=\"%.80s\"", format);
699  if (type)
700  wrbuf_printf(wr, " type=\"%.80s\"", type);
701  wrbuf_printf(wr, ">\n");
702  for (n = mt->nodes; n; n = n->next)
703  {
704  struct yaz_marc_subfield *s;
705 
706  switch(n->which)
707  {
708  case YAZ_MARC_DATAFIELD:
709 
710  wrbuf_printf(wr, " <%s", datafield_name[turbo]);
711  if (!turbo)
712  wrbuf_printf(wr, " tag=\"");
714  strlen(n->u.datafield.tag));
715  if (!turbo)
716  wrbuf_printf(wr, "\"");
717  if (n->u.datafield.indicator)
718  {
719  int i;
720  size_t off = 0;
721  for (i = 0; n->u.datafield.indicator[off]; i++)
722  {
723  size_t ilen =
725  wrbuf_printf(wr, " %s%d=\"", indicator_name[turbo], i+1);
727  n->u.datafield.indicator + off,
728  ilen);
729  off += ilen;
730  wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
731  }
732  }
733  wrbuf_printf(wr, ">\n");
734  for (s = n->u.datafield.subfields; s; s = s->next)
735  {
736  size_t using_code_len = get_subfield_len(mt, s->code_data,
737  identifier_length);
738  wrbuf_printf(wr, " <%s", subfield_name[turbo]);
739  if (!turbo)
740  {
741  wrbuf_printf(wr, " code=\"");
743  s->code_data, using_code_len);
744  wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
745  }
746  else
747  {
748  element_name_append_attribute_value(mt, wr, "code", s->code_data, using_code_len);
749  wrbuf_puts(wr, ">");
750  }
752  s->code_data + using_code_len,
753  strlen(s->code_data + using_code_len));
754  marc_iconv_reset(mt, wr);
755  wrbuf_printf(wr, "</%s", subfield_name[turbo]);
756  if (turbo)
757  element_name_append_attribute_value(mt, wr, 0, s->code_data, using_code_len);
758  wrbuf_puts(wr, ">\n");
759  }
760  wrbuf_printf(wr, " </%s", datafield_name[turbo]);
761  /* TODO Not CDATA */
762  if (turbo)
764  strlen(n->u.datafield.tag));
765  wrbuf_printf(wr, ">\n");
766  break;
768  wrbuf_printf(wr, " <%s", controlfield_name[turbo]);
769  if (!turbo)
770  {
771  wrbuf_printf(wr, " tag=\"");
773  strlen(n->u.controlfield.tag));
774  wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
775  }
776  else
777  {
778  /* TODO convert special */
780  strlen(n->u.controlfield.tag));
781  wrbuf_iconv_puts(wr, mt->iconv_cd, ">");
782  }
784  n->u.controlfield.data,
785  strlen(n->u.controlfield.data));
786  marc_iconv_reset(mt, wr);
787  wrbuf_printf(wr, "</%s", controlfield_name[turbo]);
788  /* TODO convert special */
789  if (turbo)
791  strlen(n->u.controlfield.tag));
792  wrbuf_puts(wr, ">\n");
793  break;
794  case YAZ_MARC_COMMENT:
795  wrbuf_printf(wr, "<!-- ");
796  wrbuf_puts(wr, n->u.comment);
797  wrbuf_printf(wr, " -->\n");
798  break;
799  case YAZ_MARC_LEADER:
800  wrbuf_printf(wr, " <%s>", leader_name[turbo]);
802  0 , /* no charset conversion for leader */
803  n->u.leader, strlen(n->u.leader));
804  wrbuf_printf(wr, "</%s>\n", leader_name[turbo]);
805  }
806  }
807  wrbuf_printf(wr, "</%s>\n", record_name[turbo]);
808  return 0;
809 }
810 
812  const char *ns,
813  const char *format,
814  const char *type,
815  int turbo)
816 {
817  if (mt->write_using_libxml2)
818  {
819 #if YAZ_HAVE_XML2
820  int ret;
821  xmlNode *root_ptr;
822 
823  if (!turbo)
824  ret = yaz_marc_write_xml(mt, &root_ptr, ns, format, type);
825  else
826  ret = yaz_marc_write_xml_turbo_xml(mt, &root_ptr, ns, format, type);
827  if (ret == 0)
828  {
829  xmlChar *buf_out;
830  xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
831  int len_out;
832 
833  xmlDocSetRootElement(doc, root_ptr);
834  xmlDocDumpMemory(doc, &buf_out, &len_out);
835 
836  wrbuf_write(wr, (const char *) buf_out, len_out);
837  wrbuf_puts(wr, "");
838  xmlFree(buf_out);
839  xmlFreeDoc(doc);
840  }
841  return ret;
842 #else
843  return -1;
844 #endif
845  }
846  else
847  return yaz_marc_write_marcxml_wrbuf(mt, wr, ns, format, type, turbo);
848 }
849 
851 {
852  /* set leader 09 to 'a' for UNICODE */
853  /* http://www.loc.gov/marc/bibliographic/ecbdldrd.html#mrcblea */
854  if (!mt->leader_spec)
855  yaz_marc_modify_leader(mt, 9, "a");
856  return yaz_marc_write_marcxml_ns(mt, wr,
857  "http://www.loc.gov/MARC21/slim",
858  0, 0, 0);
859 }
860 
862 {
863  /* set leader 09 to 'a' for UNICODE */
864  /* http://www.loc.gov/marc/bibliographic/ecbdldrd.html#mrcblea */
865  if (!mt->leader_spec)
866  yaz_marc_modify_leader(mt, 9, "a");
867  return yaz_marc_write_marcxml_ns(mt, wr,
868  "http://www.indexdata.com/turbomarc", 0, 0, 1);
869 }
870 
872  const char *format,
873  const char *type)
874 {
875  return yaz_marc_write_marcxml_ns(mt, wr,
876  "info:lc/xmlns/marcxchange-v1",
877  0, 0, 0);
878 }
879 
880 #if YAZ_HAVE_XML2
881 static void write_xml_indicator(yaz_marc_t mt, struct yaz_marc_node *n,
882  xmlNode *ptr, int turbo)
883 {
884  if (n->u.datafield.indicator)
885  {
886  int i;
887  size_t off = 0;
888  for (i = 0; n->u.datafield.indicator[off]; i++)
889  {
890  size_t ilen =
892  char ind_val[10];
893  if (ilen < sizeof(ind_val) - 1)
894  {
895  char ind_str[12];
896  sprintf(ind_str, "%s%d", indicator_name[turbo], i+1);
897  memcpy(ind_val, n->u.datafield.indicator + off, ilen);
898  ind_val[ilen] = '\0';
899  xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
900  }
901  off += ilen;
902  }
903  }
904 }
905 
907  struct yaz_marc_node *n,
908  xmlNode *record_ptr,
909  xmlNsPtr ns_record, WRBUF wr_cdata,
910  int identifier_length)
911 {
912  xmlNode *ptr;
913  struct yaz_marc_subfield *s;
915 
916  /* TODO consider if safe */
917  char field[10];
918  field[0] = 'd';
919  strncpy(field + 1, n->u.datafield.tag, 3);
920  field[4] = '\0';
921  ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST field, 0);
922 
923  write_xml_indicator(mt, n, ptr, 1);
924  for (s = n->u.datafield.subfields; s; s = s->next)
925  {
926  int not_written;
927  xmlNode *ptr_subfield;
928  size_t using_code_len = get_subfield_len(mt, s->code_data,
929  identifier_length);
930  wrbuf_rewind(wr_cdata);
931  wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, s->code_data + using_code_len);
932  marc_iconv_reset(mt, wr_cdata);
933 
936  not_written = element_name_append_attribute_value(mt, subfield_name, 0, s->code_data, using_code_len) != 0;
937  ptr_subfield = xmlNewTextChild(ptr, ns_record,
938  BAD_CAST wrbuf_cstr(subfield_name),
939  BAD_CAST wrbuf_cstr(wr_cdata));
940  if (not_written)
941  {
942  /* Generate code attribute value and add */
943  wrbuf_rewind(wr_cdata);
944  wrbuf_iconv_write(wr_cdata, mt->iconv_cd,s->code_data, using_code_len);
945  xmlNewProp(ptr_subfield, BAD_CAST "code", BAD_CAST wrbuf_cstr(wr_cdata));
946  }
947  }
949 }
950 
951 static int yaz_marc_write_xml_turbo_xml(yaz_marc_t mt, xmlNode **root_ptr,
952  const char *ns,
953  const char *format,
954  const char *type)
955 {
956  struct yaz_marc_node *n;
957  int identifier_length;
958  const char *leader = 0;
959  xmlNode *record_ptr;
960  xmlNsPtr ns_record;
961  WRBUF wr_cdata = 0;
962 
963  for (n = mt->nodes; n; n = n->next)
964  if (n->which == YAZ_MARC_LEADER)
965  {
966  leader = n->u.leader;
967  break;
968  }
969 
970  if (!leader)
971  return -1;
972  if (!atoi_n_check(leader+11, 1, &identifier_length))
973  return -1;
974 
975  wr_cdata = wrbuf_alloc();
976 
977  record_ptr = xmlNewNode(0, BAD_CAST "r");
978  *root_ptr = record_ptr;
979 
980  ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
981  xmlSetNs(record_ptr, ns_record);
982 
983  if (format)
984  xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
985  if (type)
986  xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
987  for (n = mt->nodes; n; n = n->next)
988  {
989  xmlNode *ptr;
990 
991  char field[10];
992  field[0] = 'c';
993  field[4] = '\0';
994 
995  switch(n->which)
996  {
997  case YAZ_MARC_DATAFIELD:
998  add_marc_datafield_turbo_xml(mt, n, record_ptr, ns_record, wr_cdata, identifier_length);
999  break;
1000  case YAZ_MARC_CONTROLFIELD:
1001  wrbuf_rewind(wr_cdata);
1002  wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
1003  marc_iconv_reset(mt, wr_cdata);
1004 
1005  strncpy(field + 1, n->u.controlfield.tag, 3);
1006  ptr = xmlNewTextChild(record_ptr, ns_record,
1007  BAD_CAST field,
1008  BAD_CAST wrbuf_cstr(wr_cdata));
1009  break;
1010  case YAZ_MARC_COMMENT:
1011  ptr = xmlNewComment(BAD_CAST n->u.comment);
1012  xmlAddChild(record_ptr, ptr);
1013  break;
1014  case YAZ_MARC_LEADER:
1015  xmlNewTextChild(record_ptr, ns_record, BAD_CAST "l",
1016  BAD_CAST n->u.leader);
1017  break;
1018  }
1019  }
1020  wrbuf_destroy(wr_cdata);
1021  return 0;
1022 }
1023 
1024 
1025 int yaz_marc_write_xml(yaz_marc_t mt, xmlNode **root_ptr,
1026  const char *ns,
1027  const char *format,
1028  const char *type)
1029 {
1030  struct yaz_marc_node *n;
1031  int identifier_length;
1032  const char *leader = 0;
1033  xmlNode *record_ptr;
1034  xmlNsPtr ns_record;
1035  WRBUF wr_cdata = 0;
1036 
1037  for (n = mt->nodes; n; n = n->next)
1038  if (n->which == YAZ_MARC_LEADER)
1039  {
1040  leader = n->u.leader;
1041  break;
1042  }
1043 
1044  if (!leader)
1045  return -1;
1046  if (!atoi_n_check(leader+11, 1, &identifier_length))
1047  return -1;
1048 
1049  wr_cdata = wrbuf_alloc();
1050 
1051  record_ptr = xmlNewNode(0, BAD_CAST "record");
1052  *root_ptr = record_ptr;
1053 
1054  ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
1055  xmlSetNs(record_ptr, ns_record);
1056 
1057  if (format)
1058  xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
1059  if (type)
1060  xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
1061  for (n = mt->nodes; n; n = n->next)
1062  {
1063  struct yaz_marc_subfield *s;
1064  xmlNode *ptr;
1065 
1066  switch(n->which)
1067  {
1068  case YAZ_MARC_DATAFIELD:
1069  ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
1070  xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
1071  write_xml_indicator(mt, n, ptr, 0);
1072  for (s = n->u.datafield.subfields; s; s = s->next)
1073  {
1074  xmlNode *ptr_subfield;
1075  size_t using_code_len = get_subfield_len(mt, s->code_data,
1076  identifier_length);
1077  wrbuf_rewind(wr_cdata);
1078  wrbuf_iconv_puts(wr_cdata, mt->iconv_cd,
1079  s->code_data + using_code_len);
1080  marc_iconv_reset(mt, wr_cdata);
1081  ptr_subfield = xmlNewTextChild(
1082  ptr, ns_record,
1083  BAD_CAST "subfield", BAD_CAST wrbuf_cstr(wr_cdata));
1084 
1085  wrbuf_rewind(wr_cdata);
1086  wrbuf_iconv_write(wr_cdata, mt->iconv_cd,
1087  s->code_data, using_code_len);
1088  xmlNewProp(ptr_subfield, BAD_CAST "code",
1089  BAD_CAST wrbuf_cstr(wr_cdata));
1090  }
1091  break;
1092  case YAZ_MARC_CONTROLFIELD:
1093  wrbuf_rewind(wr_cdata);
1094  wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
1095  marc_iconv_reset(mt, wr_cdata);
1096 
1097  ptr = xmlNewTextChild(record_ptr, ns_record,
1098  BAD_CAST "controlfield",
1099  BAD_CAST wrbuf_cstr(wr_cdata));
1100 
1101  xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
1102  break;
1103  case YAZ_MARC_COMMENT:
1104  ptr = xmlNewComment(BAD_CAST n->u.comment);
1105  xmlAddChild(record_ptr, ptr);
1106  break;
1107  case YAZ_MARC_LEADER:
1108  xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
1109  BAD_CAST n->u.leader);
1110  break;
1111  }
1112  }
1113  wrbuf_destroy(wr_cdata);
1114  return 0;
1115 }
1116 
1117 #endif
1118 
1120 {
1121  struct yaz_marc_node *n, *cap_node = 0;
1122  int indicator_length;
1123  int identifier_length;
1124  int length_data_entry;
1125  int length_starting;
1126  int length_implementation;
1127  int data_offset = 0;
1128  const char *leader = 0;
1129  WRBUF wr_dir, wr_head, wr_data_tmp;
1130  int base_address;
1131 
1132  for (n = mt->nodes; n; n = n->next)
1133  if (n->which == YAZ_MARC_LEADER)
1134  leader = n->u.leader;
1135 
1136  if (!leader)
1137  return -1;
1138  if (!atoi_n_check(leader+10, 1, &indicator_length))
1139  return -1;
1140  if (!atoi_n_check(leader+11, 1, &identifier_length))
1141  return -1;
1142  if (!atoi_n_check(leader+20, 1, &length_data_entry))
1143  return -1;
1144  if (!atoi_n_check(leader+21, 1, &length_starting))
1145  return -1;
1146  if (!atoi_n_check(leader+22, 1, &length_implementation))
1147  return -1;
1148 
1149  wr_data_tmp = wrbuf_alloc();
1150  wr_dir = wrbuf_alloc();
1151  for (n = mt->nodes; n; n = n->next)
1152  {
1153  int data_length = 0;
1154  const char *tag = 0;
1155  struct yaz_marc_subfield *s;
1156 
1157  switch(n->which)
1158  {
1159  case YAZ_MARC_DATAFIELD:
1160  tag = n->u.datafield.tag;
1161  data_length += strlen(n->u.datafield.indicator);
1162  wrbuf_rewind(wr_data_tmp);
1163  for (s = n->u.datafield.subfields; s; s = s->next)
1164  {
1165  /* write dummy IDFS + content */
1166  wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
1167  wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
1168  marc_iconv_reset(mt, wr_data_tmp);
1169  }
1170  /* write dummy FS (makes MARC-8 to become ASCII) */
1171  wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
1172  marc_iconv_reset(mt, wr_data_tmp);
1173  data_length += wrbuf_len(wr_data_tmp);
1174  break;
1175  case YAZ_MARC_CONTROLFIELD:
1176  tag = n->u.controlfield.tag;
1177  wrbuf_rewind(wr_data_tmp);
1178  wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd,
1179  n->u.controlfield.data);
1180  marc_iconv_reset(mt, wr_data_tmp);
1181  wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
1182  marc_iconv_reset(mt, wr_data_tmp);
1183  data_length += wrbuf_len(wr_data_tmp);
1184  break;
1185  case YAZ_MARC_COMMENT:
1186  break;
1187  case YAZ_MARC_LEADER:
1188  break;
1189  }
1190  if (data_length && tag)
1191  {
1192  if (wrbuf_len(wr_dir) + 40 + data_offset + data_length > 99999)
1193  {
1194  cap_node = n;
1195  break;
1196  }
1197  wrbuf_printf(wr_dir, "%3.3s", tag);
1198  wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
1199  wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
1200  data_offset += data_length;
1201  }
1202  }
1203  /* mark end of directory */
1204  wrbuf_putc(wr_dir, ISO2709_FS);
1205 
1206  /* base address of data (comes after leader+directory) */
1207  base_address = 24 + wrbuf_len(wr_dir);
1208 
1209  wr_head = wrbuf_alloc();
1210 
1211  /* write record length */
1212  wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
1213  /* from "original" leader */
1214  wrbuf_write(wr_head, leader+5, 7);
1215  /* base address of data */
1216  wrbuf_printf(wr_head, "%05d", base_address);
1217  /* from "original" leader */
1218  wrbuf_write(wr_head, leader+17, 7);
1219 
1220  wrbuf_write(wr, wrbuf_buf(wr_head), 24);
1221  wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
1222  wrbuf_destroy(wr_head);
1223  wrbuf_destroy(wr_dir);
1224  wrbuf_destroy(wr_data_tmp);
1225 
1226  for (n = mt->nodes; n != cap_node; n = n->next)
1227  {
1228  struct yaz_marc_subfield *s;
1229 
1230  switch(n->which)
1231  {
1232  case YAZ_MARC_DATAFIELD:
1233  wrbuf_puts(wr, n->u.datafield.indicator);
1234  for (s = n->u.datafield.subfields; s; s = s->next)
1235  {
1236  wrbuf_putc(wr, ISO2709_IDFS);
1237  wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
1238  marc_iconv_reset(mt, wr);
1239  }
1240  wrbuf_putc(wr, ISO2709_FS);
1241  break;
1242  case YAZ_MARC_CONTROLFIELD:
1244  marc_iconv_reset(mt, wr);
1245  wrbuf_putc(wr, ISO2709_FS);
1246  break;
1247  case YAZ_MARC_COMMENT:
1248  break;
1249  case YAZ_MARC_LEADER:
1250  break;
1251  }
1252  }
1253  wrbuf_printf(wr, "%c", ISO2709_RS);
1254  return 0;
1255 }
1256 
1258 {
1259  int identifier_length;
1260  struct yaz_marc_node *n;
1261  const char *leader = 0;
1262  int first = 1;
1263 
1264  wrbuf_puts(w, "{\n");
1265  for (n = mt->nodes; n; n = n->next)
1266  if (n->which == YAZ_MARC_LEADER)
1267  leader = n->u.leader;
1268 
1269  if (!leader)
1270  return -1;
1271 
1272  if (!atoi_n_check(leader+11, 1, &identifier_length))
1273  return -1;
1274 
1275  wrbuf_puts(w, " \"leader\": \"");
1276  wrbuf_json_puts(w, leader);
1277  wrbuf_puts(w, "\",\n");
1278  wrbuf_puts(w, " \"fields\": [");
1279 
1280  for (n = mt->nodes; n; n = n->next)
1281  {
1282  struct yaz_marc_subfield *s;
1283  const char *sep = "";
1284  switch (n->which)
1285  {
1286  case YAZ_MARC_LEADER:
1287  case YAZ_MARC_COMMENT:
1288  break;
1289  case YAZ_MARC_CONTROLFIELD:
1290  if (first)
1291  first = 0;
1292  else
1293  wrbuf_puts(w, ",");
1294  wrbuf_puts(w, "\n {\n \"");
1296  wrbuf_puts(w, "\": \"");
1298  wrbuf_puts(w, "\"\n }");
1299  break;
1300  case YAZ_MARC_DATAFIELD:
1301  if (first)
1302  first = 0;
1303  else
1304  wrbuf_puts(w, ",");
1305 
1306  wrbuf_puts(w, "\n {\n \"");
1307  wrbuf_json_puts(w, n->u.datafield.tag);
1308  wrbuf_puts(w, "\": {\n \"subfields\": [\n");
1309  for (s = n->u.datafield.subfields; s; s = s->next)
1310  {
1311  size_t using_code_len = get_subfield_len(mt, s->code_data,
1312  identifier_length);
1313  wrbuf_puts(w, sep);
1314  sep = ",\n";
1315  wrbuf_puts(w, " {\n \"");
1317  s->code_data, using_code_len);
1318  wrbuf_puts(w, "\": \"");
1320  s->code_data + using_code_len);
1321  wrbuf_puts(w, "\"\n }");
1322  }
1323  wrbuf_puts(w, "\n ]");
1324  if (n->u.datafield.indicator)
1325  {
1326  int i;
1327  size_t off = 0;
1328  for (i = 0; n->u.datafield.indicator[off]; i++)
1329  {
1330  size_t ilen =
1331  cdata_one_character(mt, n->u.datafield.indicator + off);
1332  wrbuf_printf(w, ",\n \"ind%d\": \"", i + 1);
1333  wrbuf_json_write(w, &n->u.datafield.indicator[off], ilen);
1334  wrbuf_printf(w, "\"");
1335  off += ilen;
1336  }
1337  }
1338  wrbuf_puts(w, "\n }");
1339  wrbuf_puts(w, "\n }");
1340  break;
1341  }
1342  }
1343  if (first == 0) {
1344  wrbuf_puts(w, "\n ");
1345  }
1346  wrbuf_puts(w, "]\n");
1347  wrbuf_puts(w, "}\n");
1348  return 0;
1349 }
1350 
1351 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
1352 {
1353  int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
1354  if (r <= 0)
1355  return r;
1356  s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
1357  if (s != 0)
1358  return -1; /* error */
1359  return r; /* OK, return length > 0 */
1360 }
1361 
1362 int yaz_marc_decode_buf(yaz_marc_t mt, const char *buf, int bsize,
1363  const char **result, size_t *rsize)
1364 {
1365  int r;
1366 
1367  wrbuf_rewind(mt->m_wr);
1368  r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
1369  if (result)
1370  *result = wrbuf_cstr(mt->m_wr);
1371  if (rsize)
1372  *rsize = wrbuf_len(mt->m_wr);
1373  return r;
1374 }
1375 
1376 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
1377 {
1378  mt->output_format = xmlmode;
1379 }
1380 
1381 void yaz_marc_debug(yaz_marc_t mt, int level)
1382 {
1383  if (mt)
1384  mt->debug = level;
1385 }
1386 
1388 {
1389  mt->iconv_cd = cd;
1390 }
1391 
1393 {
1394  return mt->iconv_cd;
1395 }
1396 
1397 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
1398 {
1399  struct yaz_marc_node *n;
1400  char *leader = 0;
1401  for (n = mt->nodes; n; n = n->next)
1402  if (n->which == YAZ_MARC_LEADER)
1403  {
1404  leader = n->u.leader;
1405  memcpy(leader+off, str, strlen(str));
1406  break;
1407  }
1408 }
1409 
1410 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
1411 {
1412  xfree(mt->leader_spec);
1413  mt->leader_spec = 0;
1414  if (leader_spec)
1415  {
1416  char dummy_leader[24];
1417  if (marc_exec_leader(leader_spec, dummy_leader, 24))
1418  return -1;
1419  mt->leader_spec = xstrdup(leader_spec);
1420  }
1421  return 0;
1422 }
1423 
1424 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1425 {
1426  const char *cp = leader_spec;
1427  while (cp)
1428  {
1429  char val[21];
1430  int pos;
1431  int no_read = 0, no = 0;
1432 
1433  no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1434  if (no < 2 || no_read < 3)
1435  return -1;
1436  if (pos < 0 || (size_t) pos >= size)
1437  return -1;
1438 
1439  if (*val == '\'')
1440  {
1441  const char *vp = strchr(val+1, '\'');
1442  size_t len;
1443 
1444  if (!vp)
1445  return -1;
1446  len = vp-val-1;
1447  if (len + pos > size)
1448  return -1;
1449  memcpy(leader + pos, val+1, len);
1450  }
1451  else if (*val >= '0' && *val <= '9')
1452  {
1453  int ch = atoi(val);
1454  leader[pos] = ch;
1455  }
1456  else
1457  return -1;
1458  cp += no_read;
1459  if (*cp != ',')
1460  break;
1461 
1462  cp++;
1463  }
1464  return 0;
1465 }
1466 
1467 int yaz_marc_decode_formatstr(const char *arg)
1468 {
1469  int mode = -1;
1470  if (!strcmp(arg, "marc"))
1471  mode = YAZ_MARC_ISO2709;
1472  if (!strcmp(arg, "marcxml"))
1473  mode = YAZ_MARC_MARCXML;
1474  if (!strcmp(arg, "turbomarc"))
1475  mode = YAZ_MARC_TURBOMARC;
1476  if (!strcmp(arg, "marcxchange"))
1477  mode = YAZ_MARC_XCHANGE;
1478  if (!strcmp(arg, "line"))
1479  mode = YAZ_MARC_LINE;
1480  if (!strcmp(arg, "json"))
1481  mode = YAZ_MARC_JSON;
1482  return mode;
1483 }
1484 
1486 {
1487  mt->write_using_libxml2 = enable;
1488 }
1489 
1490 int yaz_marc_check_marc21_coding(const char *charset,
1491  const char *marc_buf, int sz)
1492 {
1493  if (charset && (!yaz_matchstr(charset, "MARC8?") ||
1494  !yaz_matchstr(charset, "MARC8")) && marc_buf && sz > 25
1495  && marc_buf[9] == 'a')
1496  return 1;
1497  return 0;
1498 }
1499 
1500 /*
1501  * Local variables:
1502  * c-basic-offset: 4
1503  * c-file-style: "Stroustrup"
1504  * indent-tabs-mode: nil
1505  * End:
1506  * vim: shiftwidth=4 tabstop=8 expandtab
1507  */
1508 
int atoi_n_check(const char *buf, int size, int *val)
like atoi_n but checks for proper formatting
Definition: atoin.c:32
enum l_file_type type
Definition: log.c:47
int yaz_marc_read_iso2709(yaz_marc_t mt, const char *buf, int bsize)
read ISO2709/MARC record from buffer
int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
sets leader spec (for modifying bytes in 24 byte leader)
Definition: marcdisp.c:1410
int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
writes record in ISO2709 format
Definition: marcdisp.c:1119
void yaz_marc_add_controlfield_xml(yaz_marc_t mt, const xmlNode *ptr_tag, const xmlNode *ptr_data)
adds controlfield to MARC structure using xml Nodes
Definition: marcdisp.c:160
static int yaz_marc_write_xml_turbo_xml(yaz_marc_t mt, xmlNode **root_ptr, const char *ns, const char *format, const char *type)
Definition: marcdisp.c:951
static const char * subfield_name[2]
Definition: marcdisp.c:650
void yaz_marc_cprintf(yaz_marc_t mt, const char *fmt,...)
adds MARC annotation - printf interface
Definition: marcdisp.c:188
int yaz_marc_check_marc21_coding(const char *charset, const char *marc_buf, int sz)
check if MARC21 is UTF-8 encoded
Definition: marcdisp.c:1490
yaz_marc_t yaz_marc_create(void)
construct yaz_marc_t handle
Definition: marcdisp.c:102
int yaz_marc_write_line(yaz_marc_t mt, WRBUF wr)
writes record in line format
Definition: marcdisp.c:537
static void check_ascii(yaz_marc_t mt, char *leader, int offset, int ch_default)
Definition: marcdisp.c:344
size_t yaz_marc_sizeof_char(yaz_marc_t mt, const char *buf)
Definition: marcdisp.c:478
void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
set iconv handle for character set conversion
Definition: marcdisp.c:1387
static const char * controlfield_name[2]
Definition: marcdisp.c:647
static const char * leader_name[2]
Definition: marcdisp.c:646
void yaz_marc_add_leader(yaz_marc_t mt, const char *leader, size_t leader_len)
Definition: marcdisp.c:204
void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
set XML mode YAZ_MARC_LINE, YAZ_MARCXML, YAZ_MARC_ISO2709 ..
Definition: marcdisp.c:1376
void yaz_marc_add_subfield(yaz_marc_t mt, const char *code_data, size_t code_data_len)
adds subfield to MARC structure
Definition: marcdisp.c:316
void yaz_marc_add_datafield_xml(yaz_marc_t mt, const xmlNode *ptr_tag, const char *indicator, size_t indicator_len)
adds datafield to MARC structure using xml Nodes
Definition: marcdisp.c:284
void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
Enables or disables writing of MARC XML records using Libxml2.
Definition: marcdisp.c:1485
NMEM yaz_marc_get_nmem(yaz_marc_t mt)
returns memory for MARC handle
Definition: marcdisp.c:130
void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
Definition: marcdisp.c:438
int yaz_marc_get_debug(yaz_marc_t mt)
gets debug level for MARC system
Definition: marcdisp.c:199
static struct yaz_marc_node * yaz_marc_add_node(yaz_marc_t mt)
Definition: marcdisp.c:149
int yaz_marc_write_turbomarc(yaz_marc_t mt, WRBUF wr)
writes record in TurboMARC format
Definition: marcdisp.c:861
void yaz_marc_add_datafield(yaz_marc_t mt, const char *tag, const char *indicator, size_t indicator_len)
adds datafield to MARC structure using strings
Definition: marcdisp.c:233
YAZ_MARC_NODE_TYPE
node types for yaz_marc_node
Definition: marcdisp.c:42
@ YAZ_MARC_COMMENT
Definition: marcdisp.c:45
@ YAZ_MARC_LEADER
Definition: marcdisp.c:46
@ YAZ_MARC_DATAFIELD
Definition: marcdisp.c:43
@ YAZ_MARC_CONTROLFIELD
Definition: marcdisp.c:44
void yaz_marc_add_datafield_xml2(yaz_marc_t mt, char *tag_value, char *indicators)
adds datafield to MARC structure using xml Nodes
Definition: marcdisp.c:297
void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
modifies part of the MARC leader
Definition: marcdisp.c:1397
int yaz_marc_write_xml(yaz_marc_t mt, xmlNode **root_ptr, const char *ns, const char *format, const char *type)
writes MARC record as libxml2 tree
Definition: marcdisp.c:1025
int yaz_marc_decode_formatstr(const char *arg)
Converts MARC format type to format type(YAZ_MARC_..)
Definition: marcdisp.c:1467
int yaz_marc_write_marcxml(yaz_marc_t mt, WRBUF wr)
writes record in MARCXML format
Definition: marcdisp.c:850
static void write_xml_indicator(yaz_marc_t mt, struct yaz_marc_node *n, xmlNode *ptr, int turbo)
Definition: marcdisp.c:881
void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
Definition: marcdisp.c:432
yaz_iconv_t yaz_marc_get_iconv(yaz_marc_t mt)
supply iconv handle for character set conversion
Definition: marcdisp.c:1392
void yaz_marc_destroy(yaz_marc_t mt)
destroy yaz_marc_t handle
Definition: marcdisp.c:120
int yaz_marc_write_check(yaz_marc_t mt, WRBUF wr)
Definition: marcdisp.c:491
static const char * record_name[2]
Definition: marcdisp.c:645
static int yaz_marc_write_marcxml_wrbuf(yaz_marc_t mt, WRBUF wr, const char *ns, const char *format, const char *type, int turbo)
common MARC XML/Xchange/turbomarc writer
Definition: marcdisp.c:662
yaz_collection_state
Definition: marcdisp.c:34
@ no_collection
Definition: marcdisp.c:35
@ collection_first
Definition: marcdisp.c:36
@ collection_second
Definition: marcdisp.c:37
void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c, int *indicator_length, int *identifier_length, int *base_address, int *length_data_entry, int *length_starting, int *length_implementation)
sets leader, validates it, and returns important values
Definition: marcdisp.c:356
static void marc_iconv_reset(yaz_marc_t mt, WRBUF wr)
Definition: marcdisp.c:135
static void add_marc_datafield_turbo_xml(yaz_marc_t mt, struct yaz_marc_node *n, xmlNode *record_ptr, xmlNsPtr ns_record, WRBUF wr_cdata, int identifier_length)
Definition: marcdisp.c:906
void yaz_marc_add_controlfield_xml2(yaz_marc_t mt, char *tag, const xmlNode *ptr_data)
adds controlfield to MARC structure using xml Nodes for data
Definition: marcdisp.c:169
int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
writes record in mode - given by yaz_marc_xml mode
Definition: marcdisp.c:623
void yaz_marc_add_controlfield(yaz_marc_t mt, const char *tag, const char *data, size_t data_len)
adds controlfield to MARC structure
Definition: marcdisp.c:212
void yaz_marc_add_comment(yaz_marc_t mt, char *comment)
adds MARC comment string
Definition: marcdisp.c:181
static const char * datafield_name[2]
Definition: marcdisp.c:648
void yaz_marc_reset(yaz_marc_t mt)
clears memory and MARC record
Definition: marcdisp.c:483
int yaz_marc_write_marcxchange(yaz_marc_t mt, WRBUF wr, const char *format, const char *type)
writes record in MarcXchange XML (ISO25577)
Definition: marcdisp.c:871
int yaz_marc_write_json(yaz_marc_t mt, WRBUF w)
writes MARC record in JSON represenation
Definition: marcdisp.c:1257
void yaz_marc_enable_collection(yaz_marc_t mt)
enables record collection output
Definition: marcdisp.c:618
static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
Definition: marcdisp.c:1424
int yaz_marc_write_trailer(yaz_marc_t mt, WRBUF wr)
flushes records
Definition: marcdisp.c:600
int yaz_marc_decode_buf(yaz_marc_t mt, const char *buf, int bsize, const char **result, size_t *rsize)
decodes ISO2709 buffer using straight buffers
Definition: marcdisp.c:1362
void yaz_marc_datafield_set_indicators(struct yaz_marc_node *n, char *indicator)
Definition: marcdisp.c:309
static const char * indicator_name[2]
Definition: marcdisp.c:649
void yaz_marc_debug(yaz_marc_t mt, int level)
set debug level
Definition: marcdisp.c:1381
static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
Definition: marcdisp.c:445
int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
decodes ISO2709/MARC buffer and stores result in WRBUF
Definition: marcdisp.c:1351
static int element_name_append_attribute_value(yaz_marc_t mt, WRBUF buffer, const char *attribute_name, char *code_data, size_t code_len)
adds a attribute value to the element name if it is plain chars
Definition: marcdisp.c:253
static int yaz_marc_write_marcxml_ns(yaz_marc_t mt, WRBUF wr, const char *ns, const char *format, const char *type, int turbo)
Definition: marcdisp.c:811
static size_t get_subfield_len(yaz_marc_t mt, const char *data, int identifier_length)
Definition: marcdisp.c:525
MARC conversion.
#define YAZ_MARC_MARCXML
Output format: MARCXML.
Definition: marcdisp.h:70
#define ISO2709_FS
MARC control char: field separator (30 Dec, 1E Hex)
Definition: marcdisp.h:148
#define YAZ_MARC_XCHANGE
Output format: MarcXchange (ISO25577)
Definition: marcdisp.h:74
#define YAZ_MARC_ISO2709
Output format: ISO2709.
Definition: marcdisp.h:72
#define YAZ_MARC_LINE
Output format: Line-format.
Definition: marcdisp.h:64
#define YAZ_MARC_CHECK
Output format: check only (no marc output)
Definition: marcdisp.h:76
#define YAZ_MARC_JSON
Output format: JSON.
Definition: marcdisp.h:80
#define ISO2709_IDFS
MARC control char: identifier-field separator (31 Dec, 1F Hex)
Definition: marcdisp.h:150
#define ISO2709_RS
MARC control char: record separator (29 Dec, 1D Hex)
Definition: marcdisp.h:146
#define YAZ_MARC_TURBOMARC
Output format: Turbo MARC Index Data format (XML based)
Definition: marcdisp.h:78
struct yaz_marc_t_ * yaz_marc_t
a yaz_marc_t handle (private content)
Definition: marcdisp.h:47
int yaz_matchstr(const char *s1, const char *s2)
match strings - independent of case and '-'
Definition: matchstr.c:42
void nmem_reset(NMEM n)
releases memory associaged with an NMEM handle
Definition: nmem.c:129
NMEM nmem_create(void)
returns new NMEM handle
Definition: nmem.c:181
void * nmem_malloc(NMEM n, size_t size)
allocates memory block on NMEM handle
Definition: nmem.c:145
void nmem_destroy(NMEM n)
destroys NMEM handle and memory associated with it
Definition: nmem.c:204
Header for Nibble Memory functions + Libxml2 specific stuff.
char * nmem_text_node_cdata(const xmlNode *ptr_cdata, NMEM nmem)
copies TEXT Libxml2 node data to NMEM
Definition: nmemsdup.c:145
char * nmem_strdupn(NMEM mem, const char *src, size_t n)
allocates string of certain size on NMEM handle
Definition: nmemsdup.c:33
char * nmem_strdup(NMEM mem, const char *src)
allocates string on NMEM handle (similar strdup)
Definition: nmemsdup.c:18
size_t yaz_iconv(yaz_iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
just like iconv(3)
Definition: siconv.c:146
void yaz_vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
Definition: snprintf.c:17
Header for config file reading utilities.
string buffer
Definition: wrbuf.h:43
a comment node
Definition: marcdisp.c:63
char * comment
Definition: marcdisp.c:64
represents a control field
Definition: marcdisp.c:57
represents a data field
Definition: marcdisp.c:50
char * indicator
Definition: marcdisp.c:52
struct yaz_marc_subfield * subfields
Definition: marcdisp.c:53
MARC node.
Definition: marcdisp.c:68
struct yaz_marc_datafield datafield
Definition: marcdisp.c:71
struct yaz_marc_controlfield controlfield
Definition: marcdisp.c:72
enum YAZ_MARC_NODE_TYPE which
Definition: marcdisp.c:69
struct yaz_marc_node * next
Definition: marcdisp.c:76
char * comment
Definition: marcdisp.c:73
union yaz_marc_node::@5 u
char * leader
Definition: marcdisp.c:74
represents a subfield
Definition: marcdisp.c:80
char * code_data
Definition: marcdisp.c:81
struct yaz_marc_subfield * next
Definition: marcdisp.c:82
the internals of a yaz_marc_t handle
Definition: marcdisp.c:86
char endline_str[8]
Definition: marcdisp.c:95
enum yaz_collection_state enable_collection
Definition: marcdisp.c:92
struct yaz_marc_subfield ** subfield_pp
Definition: marcdisp.c:99
NMEM nmem
Definition: marcdisp.c:88
char * leader_spec
Definition: marcdisp.c:96
struct yaz_marc_node ** nodes_pp
Definition: marcdisp.c:98
int write_using_libxml2
Definition: marcdisp.c:91
int debug
Definition: marcdisp.c:90
WRBUF m_wr
Definition: marcdisp.c:87
int output_format
Definition: marcdisp.c:89
char subfield_str[8]
Definition: marcdisp.c:94
struct yaz_marc_node * nodes
Definition: marcdisp.c:97
yaz_iconv_t iconv_cd
Definition: marcdisp.c:93
unsigned long yaz_read_UTF8_char(const unsigned char *inp, size_t inbytesleft, size_t *no_read, int *error)
Definition: utf8.c:41
void wrbuf_destroy(WRBUF b)
destroy WRBUF and its buffer
Definition: wrbuf.c:38
void wrbuf_iconv_reset(WRBUF b, yaz_iconv_t cd)
iconv reset(flush) to WRBUF
Definition: wrbuf.c:268
void wrbuf_rewind(WRBUF b)
empty WRBUF content (length of buffer set to 0)
Definition: wrbuf.c:47
WRBUF wrbuf_alloc(void)
construct WRBUF
Definition: wrbuf.c:25
void wrbuf_iconv_putchar(WRBUF b, yaz_iconv_t cd, int ch)
iconv converts character and appends to WRBUF
Definition: wrbuf.c:240
void wrbuf_json_puts(WRBUF b, const char *str)
writes JSON text to WRBUF with escaping
Definition: wrbuf.c:354
void wrbuf_printf(WRBUF b, const char *fmt,...)
writes printf result to WRBUF
Definition: wrbuf.c:178
void wrbuf_iconv_write(WRBUF b, yaz_iconv_t cd, const char *buf, size_t size)
Converts buffer using iconv and appends to WRBUF.
Definition: wrbuf.c:230
void wrbuf_iconv_json_write(WRBUF b, yaz_iconv_t cd, const char *buf, size_t size)
Definition: wrbuf.c:257
void wrbuf_iconv_puts(WRBUF b, yaz_iconv_t cd, const char *strz)
iconv converts C-string and appends to WRBUF
Definition: wrbuf.c:235
const char * wrbuf_cstr(WRBUF b)
returns WRBUF content as C-string
Definition: wrbuf.c:281
void wrbuf_puts(WRBUF b, const char *buf)
appends C-string to WRBUF
Definition: wrbuf.c:89
void wrbuf_iconv_json_puts(WRBUF b, yaz_iconv_t cd, const char *strz)
Definition: wrbuf.c:263
void wrbuf_write(WRBUF b, const char *buf, size_t size)
append constant size buffer to WRBUF
Definition: wrbuf.c:68
void wrbuf_json_write(WRBUF b, const char *cp, size_t sz)
writes JSON text to WRBUF with escaping
Definition: wrbuf.c:319
void wrbuf_iconv_write_cdata(WRBUF b, yaz_iconv_t cd, const char *buf, size_t size)
Converts buffer using iconv and appends to WRBUF as XML CDATA.
Definition: wrbuf.c:247
Header for WRBUF (growing buffer)
#define wrbuf_putc(b, c)
Definition: wrbuf.h:268
#define wrbuf_buf(b)
Definition: wrbuf.h:251
#define wrbuf_len(b)
Definition: wrbuf.h:250
#define xstrdup(s)
utility macro which calls xstrdup_f
Definition: xmalloc.h:55
#define xfree(x)
utility macro which calls xfree_f
Definition: xmalloc.h:53
#define xmalloc(x)
utility macro which calls malloc_f
Definition: xmalloc.h:49
Header for common YAZ utilities.