Towards GPL
[idzebra-moved-to-github.git] / recctrl / marcread.c
1 /* $Id: marcread.c,v 1.17 2002-08-02 19:26:56 adam Exp $
2    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002
3    Index Data Aps
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra.  If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21 */
22
23
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <assert.h>
27
28 #include <yaz/log.h>
29 #include <yaz/yaz-util.h>
30 #include <yaz/marcdisp.h>
31 #include "grsread.h"
32
33 #define MARC_DEBUG 0
34
35 data1_node *grs_read_marc (struct grs_read_info *p)
36 {
37     char buf[100000];
38     int entry_p;
39     int record_length;
40     int indicator_length;
41     int identifier_length;
42     int base_address;
43     int length_data_entry;
44     int length_starting;
45     int length_implementation;
46     int read_bytes;
47 #if MARC_DEBUG
48     FILE *outf = stdout;
49 #endif
50     data1_node *res_root, *res_top;
51     char *absynName;
52     data1_marctab *marctab;
53
54     if ((*p->readf)(p->fh, buf, 5) != 5)
55         return NULL;
56     record_length = atoi_n (buf, 5);
57     if (record_length < 25)
58     {
59         logf (LOG_WARN, "MARC record length < 25, is %d", record_length);
60         return NULL;
61     }
62     /* read remaining part - attempt to read one byte furhter... */
63     read_bytes = (*p->readf)(p->fh, buf+5, record_length-4);
64     if (read_bytes < record_length-5)
65     {
66         logf (LOG_WARN, "Couldn't read whole MARC record");
67         return NULL;
68     }
69     if (read_bytes == record_length - 4)
70     {
71         off_t cur_offset = (*p->tellf)(p->fh);
72         if (cur_offset <= 27)
73             return NULL;
74         if (p->endf)
75             (*p->endf)(p->fh, cur_offset - 1);
76     }
77     absynName = p->type;
78     res_root = data1_mk_root (p->dh, p->mem, absynName);
79     if (!res_root)
80     {
81         yaz_log (LOG_WARN, "cannot read MARC without an abstract syntax");
82         return 0;
83     }
84     res_top = data1_mk_tag (p->dh, p->mem, absynName, 0, res_root);
85
86     marctab = res_root->u.root.absyn->marc;
87
88     if (marctab && marctab->force_indicator_length >= 0)
89         indicator_length = marctab->force_indicator_length;
90     else
91         indicator_length = atoi_n (buf+10, 1);
92     if (marctab && marctab->force_identifier_length >= 0)
93         identifier_length = marctab->force_identifier_length;
94     else
95         identifier_length = atoi_n (buf+11, 1);
96     base_address = atoi_n (buf+12, 4);
97
98     length_data_entry = atoi_n (buf+20, 1);
99     length_starting = atoi_n (buf+21, 1);
100     length_implementation = atoi_n (buf+22, 1);
101
102     for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
103         entry_p += 3+length_data_entry+length_starting;
104     base_address = entry_p+1;
105     for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
106     {
107         int data_length;
108         int data_offset;
109         int end_offset;
110         int i, i0;
111         char tag[4];
112         data1_node *res;
113         data1_node *parent = res_top;
114
115         memcpy (tag, buf+entry_p, 3);
116         entry_p += 3;
117         tag[3] = '\0';
118
119
120         /* generate field node */
121         res = data1_mk_tag_n (p->dh, p->mem, tag, 3, 0 /* attr */, parent);
122
123 #if MARC_DEBUG
124         fprintf (outf, "%s ", tag);
125 #endif
126         data_length = atoi_n (buf+entry_p, length_data_entry);
127         entry_p += length_data_entry;
128         data_offset = atoi_n (buf+entry_p, length_starting);
129         entry_p += length_starting;
130         i = data_offset + base_address;
131         end_offset = i+data_length-1;
132
133         if (memcmp (tag, "00", 2) && indicator_length)
134         {
135             /* generate indicator node */
136 #if MARC_DEBUG
137             int j;
138 #endif
139             res = data1_mk_tag_n (p->dh, p->mem, 
140                                   buf+i, indicator_length, 0 /* attr */, res);
141 #if MARC_DEBUG
142             for (j = 0; j<indicator_length; j++)
143                 fprintf (outf, "%c", buf[j+i]);
144 #endif
145             i += indicator_length;
146         }
147         parent = res;
148         /* traverse sub fields */
149         i0 = i;
150         while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset)
151         {
152             if (memcmp (tag, "00", 2) && identifier_length)
153             {
154                 data1_node *res =
155                     data1_mk_tag_n (p->dh, p->mem,
156                                     buf+i+1, identifier_length-1, 
157                                     0 /* attr */, parent);
158 #if MARC_DEBUG
159                 fprintf (outf, " $"); 
160                 for (j = 1; j<identifier_length; j++)
161                     fprintf (outf, "%c", buf[j+i]);
162                 fprintf (outf, " ");
163 #endif
164                 i += identifier_length;
165                 i0 = i;
166                 while (buf[i] != ISO2709_RS && buf[i] != ISO2709_IDFS &&
167                        buf[i] != ISO2709_FS && i < end_offset)
168                 {
169 #if MARC_DEBUG
170                     fprintf (outf, "%c", buf[i]);
171 #endif
172                     i++;
173                 }
174                 data1_mk_text_n (p->dh, p->mem, buf + i0, i - i0, res);
175                 i0 = i;
176             }
177             else
178             {
179 #if MARC_DEBUG
180                 fprintf (outf, "%c", buf[i]);
181 #endif
182                 i++;
183             }
184         }
185         if (i > i0)
186         {
187             data1_mk_text_n (p->dh, p->mem, buf + i0, i - i0, parent);
188         }
189 #if MARC_DEBUG
190         fprintf (outf, "\n");
191         if (i < end_offset)
192             fprintf (outf, "-- separator but not at end of field\n");
193         if (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
194             fprintf (outf, "-- no separator at end of field\n");
195 #endif
196     }
197     return res_root;
198
199
200 static void *grs_init_marc(void)
201 {
202     return 0;
203 }
204
205 static void grs_destroy_marc(void *clientData)
206 {
207 }
208
209 static struct recTypeGrs marc_type = {
210     "marc",
211     grs_init_marc,
212     grs_destroy_marc,
213     grs_read_marc
214 };
215
216 RecTypeGrs recTypeGrs_marc = &marc_type;