IDZEBRA 2.2.8
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
4Zebra is free software; you can redistribute it and/or modify it under
5the terms of the GNU General Public License as published by the Free
6Software Foundation; either version 2, or (at your option) any later
7version.
8
9Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or
11FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
16Foundation, 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;
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
179static 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
204static 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 */
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
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
char * data1_nodetomarc(data1_handle dh, data1_marctab *p, data1_node *n, int selected, int *len)
Definition d1_marc.c:469
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
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
data1_node * data1_get_root_tag(data1_handle dh, data1_node *n)
Definition d1_read.c:36
NMEM data1_nmem_get(data1_handle dh)
Definition d1_handle.c:66
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
FILE * data1_path_fopen(data1_handle dh, const char *file, const char *mode)
Definition d1_handle.c:147
char ** data1_get_map_buf(data1_handle dp, int **lenp)
Definition d1_handle.c:114
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