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