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