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