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