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