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