b3f5190b1388f47d7164b458b6dcec3edfe76144
[idzebra-moved-to-github.git] / recctrl / marcread.c
1 /*
2  * Copyright (C) 1997-2002, Index Data
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Id: marcread.c,v 1.16 2002-07-05 12:43:30 adam Exp $
7  */
8 #include <stdio.h>
9 #include <ctype.h>
10 #include <assert.h>
11
12 #include <yaz/log.h>
13 #include <yaz/yaz-util.h>
14 #include <yaz/marcdisp.h>
15 #include "grsread.h"
16
17 #define MARC_DEBUG 0
18
19 data1_node *grs_read_marc (struct grs_read_info *p)
20 {
21     char buf[100000];
22     int entry_p;
23     int record_length;
24     int indicator_length;
25     int identifier_length;
26     int base_address;
27     int length_data_entry;
28     int length_starting;
29     int length_implementation;
30     int read_bytes;
31 #if MARC_DEBUG
32     FILE *outf = stdout;
33 #endif
34     data1_node *res_root, *res_top;
35     char *absynName;
36     data1_marctab *marctab;
37
38     if ((*p->readf)(p->fh, buf, 5) != 5)
39         return NULL;
40     record_length = atoi_n (buf, 5);
41     if (record_length < 25)
42     {
43         logf (LOG_WARN, "MARC record length < 25, is %d", record_length);
44         return NULL;
45     }
46     /* read remaining part - attempt to read one byte furhter... */
47     read_bytes = (*p->readf)(p->fh, buf+5, record_length-4);
48     if (read_bytes < record_length-5)
49     {
50         logf (LOG_WARN, "Couldn't read whole MARC record");
51         return NULL;
52     }
53     if (read_bytes == record_length - 4)
54     {
55         off_t cur_offset = (*p->tellf)(p->fh);
56         if (cur_offset <= 27)
57             return NULL;
58         if (p->endf)
59             (*p->endf)(p->fh, cur_offset - 1);
60     }
61     absynName = p->type;
62     res_root = data1_mk_root (p->dh, p->mem, absynName);
63     if (!res_root)
64     {
65         yaz_log (LOG_WARN, "cannot read MARC without an abstract syntax");
66         return 0;
67     }
68     res_top = data1_mk_tag (p->dh, p->mem, absynName, 0, res_root);
69
70     marctab = res_root->u.root.absyn->marc;
71
72     if (marctab && marctab->force_indicator_length >= 0)
73         indicator_length = marctab->force_indicator_length;
74     else
75         indicator_length = atoi_n (buf+10, 1);
76     if (marctab && marctab->force_identifier_length >= 0)
77         identifier_length = marctab->force_identifier_length;
78     else
79         identifier_length = atoi_n (buf+11, 1);
80     base_address = atoi_n (buf+12, 4);
81
82     length_data_entry = atoi_n (buf+20, 1);
83     length_starting = atoi_n (buf+21, 1);
84     length_implementation = atoi_n (buf+22, 1);
85
86     for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
87         entry_p += 3+length_data_entry+length_starting;
88     base_address = entry_p+1;
89     for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
90     {
91         int data_length;
92         int data_offset;
93         int end_offset;
94         int i, i0;
95         char tag[4];
96         data1_node *res;
97         data1_node *parent = res_top;
98
99         memcpy (tag, buf+entry_p, 3);
100         entry_p += 3;
101         tag[3] = '\0';
102
103
104         /* generate field node */
105         res = data1_mk_tag_n (p->dh, p->mem, tag, 3, 0 /* attr */, parent);
106
107 #if MARC_DEBUG
108         fprintf (outf, "%s ", tag);
109 #endif
110         data_length = atoi_n (buf+entry_p, length_data_entry);
111         entry_p += length_data_entry;
112         data_offset = atoi_n (buf+entry_p, length_starting);
113         entry_p += length_starting;
114         i = data_offset + base_address;
115         end_offset = i+data_length-1;
116
117         if (memcmp (tag, "00", 2) && indicator_length)
118         {
119             /* generate indicator node */
120 #if MARC_DEBUG
121             int j;
122 #endif
123             res = data1_mk_tag_n (p->dh, p->mem, 
124                                   buf+i, indicator_length, 0 /* attr */, res);
125 #if MARC_DEBUG
126             for (j = 0; j<indicator_length; j++)
127                 fprintf (outf, "%c", buf[j+i]);
128 #endif
129             i += indicator_length;
130         }
131         parent = res;
132         /* traverse sub fields */
133         i0 = i;
134         while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset)
135         {
136             if (memcmp (tag, "00", 2) && identifier_length)
137             {
138                 data1_node *res =
139                     data1_mk_tag_n (p->dh, p->mem,
140                                     buf+i+1, identifier_length-1, 
141                                     0 /* attr */, parent);
142 #if MARC_DEBUG
143                 fprintf (outf, " $"); 
144                 for (j = 1; j<identifier_length; j++)
145                     fprintf (outf, "%c", buf[j+i]);
146                 fprintf (outf, " ");
147 #endif
148                 i += identifier_length;
149                 i0 = i;
150                 while (buf[i] != ISO2709_RS && buf[i] != ISO2709_IDFS &&
151                        buf[i] != ISO2709_FS && i < end_offset)
152                 {
153 #if MARC_DEBUG
154                     fprintf (outf, "%c", buf[i]);
155 #endif
156                     i++;
157                 }
158                 data1_mk_text_n (p->dh, p->mem, buf + i0, i - i0, res);
159                 i0 = i;
160             }
161             else
162             {
163 #if MARC_DEBUG
164                 fprintf (outf, "%c", buf[i]);
165 #endif
166                 i++;
167             }
168         }
169         if (i > i0)
170         {
171             data1_mk_text_n (p->dh, p->mem, buf + i0, i - i0, parent);
172         }
173 #if MARC_DEBUG
174         fprintf (outf, "\n");
175         if (i < end_offset)
176             fprintf (outf, "-- separator but not at end of field\n");
177         if (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
178             fprintf (outf, "-- no separator at end of field\n");
179 #endif
180     }
181     return res_root;
182
183
184 static void *grs_init_marc(void)
185 {
186     return 0;
187 }
188
189 static void grs_destroy_marc(void *clientData)
190 {
191 }
192
193 static struct recTypeGrs marc_type = {
194     "marc",
195     grs_init_marc,
196     grs_destroy_marc,
197     grs_read_marc
198 };
199
200 RecTypeGrs recTypeGrs_marc = &marc_type;