0edc5d441ef1aed5e4dd1a46c7cd6a4001fda588
[idzebra-moved-to-github.git] / recctrl / marcread.c
1 /*
2  * Copyright (C) 1997-1999, Index Data
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: marcread.c,v $
7  * Revision 1.7  1999-05-20 12:57:18  adam
8  * Implemented TCL filter. Updated recctrl system.
9  *
10  * Revision 1.6  1999/02/02 14:51:27  adam
11  * Updated WIN32 code specific sections. Changed header.
12  *
13  * Revision 1.5  1997/11/18 10:03:24  adam
14  * Member num_children removed from data1_node.
15  *
16  * Revision 1.4  1997/10/27 14:34:26  adam
17  * Fixed bug - data1 root node wasn't tagged at all!
18  *
19  * Revision 1.3  1997/09/24 13:36:51  adam
20  * *** empty log message ***
21  *
22  * Revision 1.2  1997/09/17 12:19:21  adam
23  * Zebra version corresponds to YAZ version 1.4.
24  * Changed Zebra server so that it doesn't depend on global common_resource.
25  *
26  * Revision 1.1  1997/09/04 13:54:40  adam
27  * Added MARC filter - type grs.marc.<syntax> where syntax refers
28  * to abstract syntax. New method tellf in retrieve/extract method.
29  *
30  */
31 #include <stdio.h>
32 #include <ctype.h>
33 #include <assert.h>
34
35 #include <log.h>
36 #include <yaz-util.h>
37 #include <marcdisp.h>
38 #include "grsread.h"
39
40 data1_node *data1_mk_node_wp (data1_handle dh, NMEM mem, data1_node *parent)
41 {
42     data1_node *res = data1_mk_node (dh, mem);
43     
44     if (!parent)
45         res->root = res;
46     else
47     {
48         res->root = parent->root;
49         res->parent = parent;
50         if (!parent->child)
51             parent->child = parent->last_child = res;
52         else
53             parent->last_child->next = res;
54         parent->last_child = res;
55     }
56     return res;
57 }
58
59 static void destroy_data (struct data1_node *n)
60 {
61     assert (n->which == DATA1N_data);
62     xfree (n->u.data.data);
63 }
64
65 data1_node *data1_mk_node_text (data1_handle dh, NMEM mem, data1_node *parent,
66                                 const char *buf, size_t len)
67 {
68     data1_node *res = data1_mk_node_wp (dh, mem, parent);
69     res->which = DATA1N_data;
70     res->u.data.formatted_text = 0;
71     res->u.data.what = DATA1I_text;
72     res->u.data.len = len;
73     if (res->u.data.len > DATA1_LOCALDATA) {
74         res->u.data.data = xmalloc (res->u.data.len);
75         res->destroy = destroy_data;
76     }
77     else
78         res->u.data.data = res->lbuf;
79     memcpy (res->u.data.data, buf, res->u.data.len);
80     return res;
81 }
82
83 data1_node *data1_mk_node_tag (data1_handle dh, NMEM mem, data1_node *parent,
84                                const char *tag, size_t len)
85 {
86     data1_element *elem = NULL;
87     data1_node *partag = get_parent_tag(dh, parent);
88     data1_node *res;
89     data1_element *e = NULL;
90     int localtag = 0;
91     
92     res = data1_mk_node_wp (dh, mem, parent);
93
94     res->which = DATA1N_tag;
95     res->u.tag.tag = res->lbuf;
96     res->u.tag.get_bytes = -1;
97
98     if (len >= DATA1_LOCALDATA)
99         len = DATA1_LOCALDATA-1;
100
101     memcpy (res->u.tag.tag, tag, len);
102     res->u.tag.tag[len] = '\0';
103    
104     if (parent->which == DATA1N_variant)
105         return res;
106     if (partag)
107         if (!(e = partag->u.tag.element))
108             localtag = 1;
109     
110     elem = data1_getelementbytagname (dh, res->root->u.root.absyn, e,
111                                       res->u.tag.tag);
112     res->u.tag.element = elem;
113     res->u.tag.node_selected = 0;
114     res->u.tag.make_variantlist = 0;
115     res->u.tag.no_data_requested = 0;
116     return res;
117 }
118
119 #define MARC_DEBUG 0
120
121 data1_node *grs_read_marc (struct grs_read_info *p)
122 {
123     char buf[100000];
124     int entry_p;
125     int record_length;
126     int indicator_length;
127     int identifier_length;
128     int base_address;
129     int length_data_entry;
130     int length_starting;
131     int length_implementation;
132     int read_bytes;
133 #if MARC_DEBUG
134     FILE *outf = stdout;
135 #endif
136
137     data1_node *res_root;
138     data1_absyn *absyn;
139     char *absynName;
140     data1_marctab *marctab;
141
142     if ((*p->readf)(p->fh, buf, 5) != 5)
143         return NULL;
144     record_length = atoi_n (buf, 5);
145     if (record_length < 25)
146     {
147         logf (LOG_WARN, "MARC record length < 25, is %d", record_length);
148         return NULL;
149     }
150     /* read remaining part - attempt to read one byte furhter... */
151     read_bytes = (*p->readf)(p->fh, buf+5, record_length-4);
152     if (read_bytes < record_length-5)
153     {
154         logf (LOG_WARN, "Couldn't read whole MARC record");
155         return NULL;
156     }
157     if (read_bytes == record_length - 4)
158     {
159         off_t cur_offset = (*p->tellf)(p->fh);
160         assert (cur_offset > 26);
161         if (p->endf)
162             (*p->endf)(p->fh, cur_offset - 1);
163     }
164     absynName = p->type;
165     logf (LOG_DEBUG, "absynName = %s", absynName);
166     if (!(absyn = data1_get_absyn (p->dh, absynName)))
167     {
168         logf (LOG_WARN, "Unknown abstract syntax: %s", absynName);
169         return NULL;
170     }
171     res_root = data1_mk_node_wp (p->dh, p->mem, NULL);
172     res_root->which = DATA1N_root;
173     res_root->u.root.type = nmem_malloc (p->mem, strlen(absynName)+1);
174     strcpy (res_root->u.root.type, absynName);
175     res_root->u.root.absyn = absyn;
176
177     marctab = absyn->marc;
178
179     if (marctab && marctab->force_indicator_length >= 0)
180         indicator_length = marctab->force_indicator_length;
181     else
182         indicator_length = atoi_n (buf+10, 1);
183     if (marctab && marctab->force_identifier_length >= 0)
184         identifier_length = marctab->force_identifier_length;
185     else
186         identifier_length = atoi_n (buf+11, 1);
187     base_address = atoi_n (buf+12, 4);
188
189
190     length_data_entry = atoi_n (buf+20, 1);
191     length_starting = atoi_n (buf+21, 1);
192     length_implementation = atoi_n (buf+22, 1);
193
194     for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
195         entry_p += 3+length_data_entry+length_starting;
196     base_address = entry_p+1;
197     for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
198     {
199         int data_length;
200         int data_offset;
201         int end_offset;
202         int i, i0;
203         char tag[4];
204         data1_node *res;
205         data1_node *parent = res_root;
206
207         memcpy (tag, buf+entry_p, 3);
208         entry_p += 3;
209         tag[3] = '\0';
210
211         /* generate field node */
212         res = data1_mk_node_tag (p->dh, p->mem, res_root, tag, 3);
213
214 #if MARC_DEBUG
215         fprintf (outf, "%s ", tag);
216 #endif
217         data_length = atoi_n (buf+entry_p, length_data_entry);
218         entry_p += length_data_entry;
219         data_offset = atoi_n (buf+entry_p, length_starting);
220         entry_p += length_starting;
221         i = data_offset + base_address;
222         end_offset = i+data_length-1;
223
224         if (memcmp (tag, "00", 2) && indicator_length)
225         {
226             /* generate indicator node */
227 #if MARC_DEBUG
228             int j;
229 #endif
230             res = data1_mk_node_tag (p->dh, p->mem, res, buf+i,
231                                      indicator_length);
232 #if MARC_DEBUG
233             for (j = 0; j<indicator_length; j++)
234                 fprintf (outf, "%c", buf[j+i]);
235 #endif
236             i += indicator_length;
237         }
238         parent = res;
239         /* traverse sub fields */
240         i0 = i;
241         while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset)
242         {
243             if (memcmp (tag, "00", 2) && identifier_length)
244             {
245                 data1_node *res =
246                     data1_mk_node_tag (p->dh, p->mem, parent,
247                                        buf+i+1, identifier_length-1);
248 #if MARC_DEBUG
249                 fprintf (outf, " $"); 
250                 for (j = 1; j<identifier_length; j++)
251                     fprintf (outf, "%c", buf[j+i]);
252                 fprintf (outf, " ");
253 #endif
254                 i += identifier_length;
255                 i0 = i;
256                 while (buf[i] != ISO2709_RS && buf[i] != ISO2709_IDFS &&
257                        buf[i] != ISO2709_FS && i < end_offset)
258                 {
259 #if MARC_DEBUG
260                     fprintf (outf, "%c", buf[i]);
261 #endif
262                     i++;
263                 }
264                 data1_mk_node_text (p->dh, p->mem, res, buf + i0, i - i0);
265                 i0 = i;
266             }
267             else
268             {
269 #if MARC_DEBUG
270                 fprintf (outf, "%c", buf[i]);
271 #endif
272                 i++;
273             }
274         }
275         if (i > i0)
276         {
277             data1_node *res = data1_mk_node_tag (p->dh, p->mem,
278                                                  parent, "@", 1);
279             data1_mk_node_text (p->dh, p->mem, res, buf + i0, i - i0);
280         }
281 #if MARC_DEBUG
282         fprintf (outf, "\n");
283         if (i < end_offset)
284             fprintf (outf, "-- separator but not at end of field\n");
285         if (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
286             fprintf (outf, "-- no separator at end of field\n");
287 #endif
288     }
289     return res_root;
290
291
292 static void *grs_init_marc()
293 {
294     return 0;
295 }
296
297 static void grs_destroy_marc(void *clientData)
298 {
299 }
300
301 static struct recTypeGrs marc_type = {
302     "marc",
303     grs_init_marc,
304     grs_destroy_marc,
305     grs_read_marc
306 };
307
308 RecTypeGrs recTypeGrs_marc = &marc_type;