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