IDZEBRA  2.2.7
d1_marc.c
Go to the documentation of this file.
1 /* This file is part of the Zebra server.
2  Copyright (C) Index Data
3 
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8 
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 
18 */
19 
20 /* converts data1 tree to ISO2709/MARC record */
21 
22 #if HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <assert.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include <yaz/log.h>
30 #include <yaz/snprintf.h>
31 #include <yaz/oid_db.h>
32 #include <yaz/marcdisp.h>
33 #include <yaz/readconf.h>
34 #include <yaz/xmalloc.h>
35 #include <yaz/tpath.h>
36 #include <idzebra/data1.h>
37 
39 {
40  FILE *f;
41  NMEM mem = data1_nmem_get (dh);
42  data1_marctab *res = (data1_marctab *)nmem_malloc(mem, sizeof(*res));
43  char line[512], *argv[50];
44  int lineno = 0;
45  int argc;
46 
47  if (!(f = data1_path_fopen(dh, file, "r")))
48  return 0;
49 
50  res->name = 0;
51  res->oid = 0;
52  res->next = 0;
53  res->length_data_entry = 4;
54  res->length_starting = 5;
55  res->length_implementation = 0;
56  strcpy(res->future_use, "4");
57 
58  strcpy(res->record_status, "n");
59  strcpy(res->implementation_codes, " ");
60  res->indicator_length = 2;
61  res->identifier_length = 2;
62  res->force_indicator_length = -1;
63  res->force_identifier_length = -1;
64  strcpy(res->user_systems, "z ");
65 
66  while ((argc = readconf_line(f, &lineno, line, 512, argv, 50)))
67  if (!strcmp(*argv, "name"))
68  {
69  if (argc != 2)
70  {
71  yaz_log(YLOG_WARN, "%s:%d:Missing arg for %s", file, lineno,
72  *argv);
73  continue;
74  }
75  res->name = nmem_strdup(mem, argv[1]);
76  }
77  else if (!strcmp(*argv, "reference"))
78  {
79  if (argc != 2)
80  {
81  yaz_log(YLOG_WARN, "%s:%d: Missing arg for %s", file, lineno,
82  *argv);
83  continue;
84  }
85  res->oid = yaz_string_to_oid_nmem(yaz_oid_std(),
86  CLASS_TAGSET, argv[1],
87  mem);
88  if (!res->oid)
89  {
90  yaz_log(YLOG_WARN, "%s:%d: Unknown tagset reference '%s'",
91  file, lineno, argv[1]);
92  continue;
93  }
94  }
95  else if (!strcmp(*argv, "length-data-entry"))
96  {
97  if (argc != 2)
98  {
99  yaz_log(YLOG_WARN, "%s:%d: Missing arg for %s", file, lineno,
100  *argv);
101  continue;
102  }
103  res->length_data_entry = atoi(argv[1]);
104  }
105  else if (!strcmp(*argv, "length-starting"))
106  {
107  if (argc != 2)
108  {
109  yaz_log(YLOG_WARN, "%s:%d: Missing arg for %s", file, lineno,
110  *argv);
111  continue;
112  }
113  res->length_starting = atoi(argv[1]);
114  }
115  else if (!strcmp(*argv, "length-implementation"))
116  {
117  if (argc != 2)
118  {
119  yaz_log(YLOG_WARN, "%s:%d: Missing arg for %s", file, lineno,
120  *argv);
121  continue;
122  }
123  res->length_implementation = atoi(argv[1]);
124  }
125  else if (!strcmp(*argv, "future-use"))
126  {
127  if (argc != 2)
128  {
129  yaz_log(YLOG_WARN, "%s:%d: Missing arg for %s", file, lineno,
130  *argv);
131  continue;
132  }
133  res->future_use[0] = argv[1][0]; /* use[1] already \0 */
134  }
135  else if (!strcmp(*argv, "force-indicator-length"))
136  {
137  if (argc != 2)
138  {
139  yaz_log(YLOG_WARN, "%s:%d: Missing arg for %s", file, lineno,
140  *argv);
141  continue;
142  }
143  res->force_indicator_length = atoi(argv[1]);
144  }
145  else if (!strcmp(*argv, "force-identifier-length"))
146  {
147  if (argc != 2)
148  {
149  yaz_log(YLOG_WARN, "%s:%d: Missing arg for %s", file, lineno,
150  *argv);
151  continue;
152  }
153  res->force_identifier_length = atoi(argv[1]);
154  }
155  else if (!strcmp(*argv, "implementation-codes"))
156  {
157  if (argc != 2)
158  {
159  yaz_log(YLOG_WARN, "%s:%d: Missing arg for %s", file, lineno,
160  *argv);
161  continue;
162  }
163  /* up to 4 characters .. space pad */
164  if (strlen(argv[1]) > 4)
165  yaz_log(YLOG_WARN, "%s:%d: Max 4 characters for "
166  "implementation-codes", file, lineno);
167  else
168  memcpy(res->implementation_codes, argv[1], strlen(argv[1]));
169  }
170  else
171  yaz_log(YLOG_WARN, "%s:%d: Unknown directive '%s'", file, lineno,
172  *argv);
173 
174  fclose(f);
175  return res;
176 }
177 
178 
179 static void get_data2(data1_node *n, int *len, char *dst, size_t max)
180 {
181  *len = 0;
182  while (n)
183  {
184  if (n->which == DATA1N_data)
185  {
186  if (dst && *len < max)
187  {
188  size_t copy_len = max - *len;
189  if (copy_len > n->u.data.len)
190  copy_len = n->u.data.len;
191  memcpy(dst + *len, n->u.data.data, copy_len);
192  }
193  *len += n->u.data.len;
194  }
195  if (n->which == DATA1N_tag && *len == 0)
196  n = n->child;
197  else if (n->which == DATA1N_data)
198  n = n->next;
199  else
200  break;
201  }
202 }
203 
204 static void memint(char *p, int val, int len)
205 {
206  char buf[10];
207 
208  if (len == 1)
209  *p = val + '0';
210  else
211  {
212  yaz_snprintf(buf, sizeof(buf), "%08d", val);
213  memcpy(p, buf+8-len, len);
214  }
215 }
216 
217 /* check for indicator. non MARCXML only */
218 static int is_indicator(data1_marctab *p, data1_node *subf)
219 {
220  if (p->indicator_length != 2 ||
221  (subf && subf->which == DATA1N_tag && strlen(subf->u.tag.tag) == 2))
222  return 1;
223  return 0;
224 }
225 
226 static int nodetomarc(data1_handle dh,
227  data1_marctab *p, data1_node *n, int selected,
228  char **buf, int *size)
229 {
230  char leader[24];
231 
232  int len = 26;
233  int dlen;
234  int base_address = 25;
235  int entry_p, data_p;
236  char *op;
237  data1_node *field, *subf;
238 
239 #if 0
240  data1_pr_tree(dh, n, stdout);
241 #endif
242  yaz_log(YLOG_DEBUG, "nodetomarc");
243 
244  memcpy(leader+5, p->record_status, 1);
245  memcpy(leader+6, p->implementation_codes, 4);
246  memint(leader+10, p->indicator_length, 1);
247  memint(leader+11, p->identifier_length, 1);
248  memcpy(leader+17, p->user_systems, 3);
249  memint(leader+20, p->length_data_entry, 1);
250  memint(leader+21, p->length_starting, 1);
251  memint(leader+22, p->length_implementation, 1);
252  memcpy(leader+23, p->future_use, 1);
253 
254  for (field = n->child; field; field = field->next)
255  {
256  int control_field = 0; /* 00X fields - usually! */
257  int marc_xml = 0;
258 
259  if (field->which != DATA1N_tag)
260  continue;
261  if (selected && !field->u.tag.node_selected)
262  continue;
263 
264  subf = field->child;
265  if (!subf)
266  continue;
267 
268  if (!yaz_matchstr(field->u.tag.tag, "mc?"))
269  continue;
270  else if (!strcmp(field->u.tag.tag, "leader"))
271  {
272  int dlen = 0;
273  get_data2(subf, &dlen, leader, 24);
274  continue;
275  }
276  else if (!strcmp(field->u.tag.tag, "controlfield"))
277  {
278  control_field = 1;
279  marc_xml = 1;
280  }
281  else if (!strcmp(field->u.tag.tag, "datafield"))
282  {
283  control_field = 0;
284  marc_xml = 1;
285  }
286  else if (subf->which == DATA1N_data)
287  {
288  control_field = 1;
289  marc_xml = 0;
290  }
291  else
292  {
293  control_field = 0;
294  marc_xml = 0;
295  }
296 
297  len += 4 + p->length_data_entry + p->length_starting
299  base_address += 3 + p->length_data_entry + p->length_starting
301 
302  if (!control_field)
303  len += p->indicator_length;
304 
305  /* we'll allow no indicator if length is not 2 */
306  /* select when old XML format, since indicator is an element */
307  if (marc_xml == 0 && is_indicator (p, subf))
308  subf = subf->child;
309 
310  for (; subf; subf = subf->next)
311  {
312  if (!control_field)
313  {
314  if (marc_xml && subf->which != DATA1N_tag)
315  continue; /* we skip comments, cdata .. */
316  len += p->identifier_length;
317  }
318  get_data2(subf, &dlen, 0, 0);
319  len += dlen;
320  }
321  }
322 
323  if (!*buf)
324  *buf = (char *)xmalloc(*size = len);
325  else if (*size <= len)
326  *buf = (char *)xrealloc(*buf, *size = len);
327 
328  op = *buf;
329 
330  /* we know the base address now */
331  memint(leader+12, base_address, 5);
332 
333  /* copy temp leader to real output buf op */
334  memcpy(op, leader, 24);
335  memint(op, len, 5);
336 
337  entry_p = 24;
338  data_p = base_address;
339 
340  for (field = n->child; field; field = field->next)
341  {
342  int control_field = 0;
343  int marc_xml = 0;
344  const char *tag = 0;
345 
346  int data_0 = data_p;
347  char indicator_data[6];
348 
349  memset(indicator_data, ' ', sizeof(indicator_data) - 1);
350  indicator_data[sizeof(indicator_data)-1] = '\0';
351 
352  if (field->which != DATA1N_tag)
353  continue;
354 
355  if (selected && !field->u.tag.node_selected)
356  continue;
357 
358  subf = field->child;
359  if (!subf)
360  continue;
361 
362  if (!yaz_matchstr(field->u.tag.tag, "mc?"))
363  continue;
364  else if (!strcmp(field->u.tag.tag, "leader"))
365  continue;
366  else if (!strcmp(field->u.tag.tag, "controlfield"))
367  {
368  control_field = 1;
369  marc_xml = 1;
370  }
371  else if (!strcmp(field->u.tag.tag, "datafield"))
372  {
373  control_field = 0;
374  marc_xml = 1;
375  }
376  else if (subf->which == DATA1N_data)
377  {
378  control_field = 1;
379  marc_xml = 0;
380  }
381  else
382  {
383  control_field = 0;
384  marc_xml = 0;
385  }
386  if (marc_xml == 0 && is_indicator(p, subf))
387  {
388  if (strlen(subf->u.tag.tag) < sizeof(indicator_data))
389  strcpy(indicator_data, subf->u.tag.tag);
390  subf = subf->child;
391  }
392  else if (marc_xml == 1 && !control_field)
393  {
394  data1_xattr *xa;
395  for (xa = field->u.tag.attributes; xa; xa = xa->next)
396  {
397  if (!strcmp(xa->name, "ind1"))
398  indicator_data[0] = xa->value[0];
399  if (!strcmp(xa->name, "ind2"))
400  indicator_data[1] = xa->value[0];
401  if (!strcmp(xa->name, "ind3"))
402  indicator_data[2] = xa->value[0];
403  }
404  }
405  if (!control_field)
406  {
407  memcpy(op + data_p, indicator_data, p->indicator_length);
408  data_p += p->indicator_length;
409  }
410  for (; subf; subf = subf->next)
411  {
412  if (!control_field)
413  {
414  const char *identifier = "a";
415  if (marc_xml)
416  {
417  data1_xattr *xa;
418  if (subf->which != DATA1N_tag)
419  continue;
420  if (strcmp(subf->u.tag.tag, "subfield"))
421  yaz_log(YLOG_WARN, "Unhandled tag %s",
422  subf->u.tag.tag);
423 
424  for (xa = subf->u.tag.attributes; xa; xa = xa->next)
425  if (!strcmp(xa->name, "code"))
426  identifier = xa->value;
427  }
428  else if (subf->which != DATA1N_tag)
429  yaz_log(YLOG_WARN, "Malformed fields for marc output.");
430  else
431  identifier = subf->u.tag.tag;
432  op[data_p] = ISO2709_IDFS;
433  memcpy(op + data_p+1, identifier, p->identifier_length-1);
434  data_p += p->identifier_length;
435  }
436  get_data2(subf, &dlen, op + data_p, 100000);
437  data_p += dlen;
438  }
439  op[data_p++] = ISO2709_FS;
440 
441  if (marc_xml)
442  {
443  data1_xattr *xa;
444  for (xa = field->u.tag.attributes; xa; xa = xa->next)
445  if (!strcmp(xa->name, "tag"))
446  tag = xa->value;
447  }
448  else
449  tag = field->u.tag.tag;
450 
451  if (!tag || strlen(tag) != 3)
452  tag = "000";
453  memcpy(op + entry_p, tag, 3);
454 
455  entry_p += 3;
456  memint(op + entry_p, data_p - data_0, p->length_data_entry);
457  entry_p += p->length_data_entry;
458  memint(op + entry_p, data_0 - base_address, p->length_starting);
459  entry_p += p->length_starting;
460  entry_p += p->length_implementation;
461  }
462  op[entry_p++] = ISO2709_FS;
463  assert (entry_p == base_address);
464  op[data_p++] = ISO2709_RS;
465  assert (data_p == len);
466  return len;
467 }
468 
470  int selected, int *len)
471 {
472  int *size;
473  char **buf = data1_get_map_buf(dh, &size);
474 
475  n = data1_get_root_tag(dh, n);
476  if (!n)
477  return 0;
478  *len = nodetomarc(dh, p, n, selected, buf, size);
479  return *buf;
480 }
481 /*
482  * Local variables:
483  * c-basic-offset: 4
484  * c-file-style: "Stroustrup"
485  * indent-tabs-mode: nil
486  * End:
487  * vim: shiftwidth=4 tabstop=8 expandtab
488  */
489 
data1_marctab * data1_read_marctab(data1_handle dh, const char *file)
Definition: d1_marc.c:38
static void memint(char *p, int val, int len)
Definition: d1_marc.c:204
char * data1_nodetomarc(data1_handle dh, data1_marctab *p, data1_node *n, int selected, int *len)
Definition: d1_marc.c:469
static void get_data2(data1_node *n, int *len, char *dst, size_t max)
Definition: d1_marc.c:179
static int is_indicator(data1_marctab *p, data1_node *subf)
Definition: d1_marc.c:218
static int nodetomarc(data1_handle dh, data1_marctab *p, data1_node *n, int selected, char **buf, int *size)
Definition: d1_marc.c:226
char ** data1_get_map_buf(data1_handle dp, int **lenp)
Definition: d1_handle.c:114
FILE * data1_path_fopen(data1_handle dh, const char *file, const char *mode)
Definition: d1_handle.c:147
NMEM data1_nmem_get(data1_handle dh)
Definition: d1_handle.c:66
data1_node * data1_get_root_tag(data1_handle dh, data1_node *n)
Definition: d1_read.c:36
void data1_pr_tree(data1_handle dh, data1_node *n, FILE *out)
Definition: d1_prtree.c:134
#define DATA1N_tag
Definition: data1.h:276
#define DATA1N_data
Definition: data1.h:278
int length_implementation
Definition: data1.h:150
int force_indicator_length
Definition: data1.h:153
char * name
Definition: data1.h:139
char implementation_codes[5]
Definition: data1.h:143
char future_use[2]
Definition: data1.h:151
int length_starting
Definition: data1.h:149
int indicator_length
Definition: data1.h:144
char user_systems[4]
Definition: data1.h:146
int identifier_length
Definition: data1.h:145
int length_data_entry
Definition: data1.h:148
int force_identifier_length
Definition: data1.h:154
char record_status[2]
Definition: data1.h:142
struct data1_marctab * next
Definition: data1.h:156
Odr_oid * oid
Definition: data1.h:140
struct data1_node * child
Definition: data1.h:341
char * tag
Definition: data1.h:296
char * data
Definition: data1.h:307
struct data1_node * next
Definition: data1.h:340
union data1_node::@2 u
int which
Definition: data1.h:285
char * value
Definition: data1.h:261
char * name
Definition: data1.h:260
struct data1_xattr * next
Definition: data1.h:262