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