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