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