YAZ 5.35.1
marc_read_line.c
Go to the documentation of this file.
1/* This file is part of the YAZ toolkit.
2 * Copyright (C) Index Data
3 * See the file LICENSE for details.
4 */
5
11#if HAVE_CONFIG_H
12#include <config.h>
13#endif
14
15#ifdef WIN32
16#include <windows.h>
17#endif
18
19#include <assert.h>
20#include <stdio.h>
21#include <string.h>
22
23#include <yaz/marcdisp.h>
24#include <yaz/wrbuf.h>
25#include <yaz/yaz-util.h>
26
27static int yaz_gets(int (*getbyte)(void *client_data),
28 void (*ungetbyte)(int b, void *client_data),
29 void *client_data,
30 WRBUF w)
31{
32 size_t sz = 0;
33 int ch = getbyte(client_data);
34
35 while (ch != '\0' && ch != '\r' && ch != '\n')
36 {
37 wrbuf_putc(w, ch);
38 sz++;
39 ch = getbyte(client_data);
40 }
41 if (ch == '\r')
42 {
43 ch = getbyte(client_data);
44 if (ch != '\n' && ch != '\0')
45 ungetbyte(ch, client_data);
46 }
47 else if (ch == '\n')
48 {
49 ch = getbyte(client_data);
50 if (ch != '\r' && ch != '\0')
51 ungetbyte(ch, client_data);
52 }
53 if (sz)
54 {
55 return 1;
56 }
57 return 0;
58}
59
60static int yaz_marc_line_gets(int (*getbyte)(void *client_data),
61 void (*ungetbyte)(int b, void *client_data),
62 void *client_data,
63 WRBUF w)
64{
65 int more;
66
67 wrbuf_rewind(w);
68 more = yaz_gets(getbyte, ungetbyte, client_data, w);
69 if (!more)
70 return 0;
71
72 while (more)
73 {
74 int i;
75 for (i = 0; i<4; i++)
76 {
77 int ch = getbyte(client_data);
78 if (ch != ' ')
79 {
80 if (ch)
81 ungetbyte(ch, client_data);
82 return 1;
83 }
84 }
85 if (wrbuf_len(w) > 60 && wrbuf_buf(w)[wrbuf_len(w)-1] == '=')
86 wrbuf_cut_right(w, 1);
87 else
88 wrbuf_puts(w, " ");
89 more = yaz_gets(getbyte, ungetbyte, client_data, w);
90 }
91 return 1;
92}
93
94
96 int (*getbyte)(void *client_data),
97 void (*ungetbyte)(int b, void *client_data),
98 void *client_data)
99{
100 int indicator_length;
101 int identifier_length;
102 int base_address;
103 int length_data_entry;
104 int length_starting;
105 int length_implementation;
106 int marker_ch = 0;
107 int marker_skip = 0;
108 int header_created = 0;
109 WRBUF wrbuf_line = wrbuf_alloc();
110
111 yaz_marc_reset(mt);
112
113 while (yaz_marc_line_gets(getbyte, ungetbyte, client_data, wrbuf_line))
114 {
115 const char *line = wrbuf_cstr(wrbuf_line);
116 int val;
117 size_t line_len = strlen(line);
118 if (line_len == 0) /* empty line indicates end of record */
119 {
120 if (header_created)
121 break;
122 }
123 else if (line[0] == '$') /* indicates beginning/end of record */
124 {
125 if (header_created)
126 break;
127 }
128 else if (line[0] == '(') /* annotation, skip it */
129 ;
130 else if (line_len == 24 && atoi_n_check(line, 5, &val))
131 {
132 /* deal with header lines: 00366nam 22001698a 4500
133 */
134
135 if (header_created)
136 break;
137 yaz_marc_set_leader(mt, line,
138 &indicator_length,
139 &identifier_length,
140 &base_address,
141 &length_data_entry,
142 &length_starting,
143 &length_implementation);
144 header_created = 1;
145 }
146 else if (line_len > 4 && line[0] != ' ' && line[1] != ' '
147 && line[2] != ' ' && line[3] == ' ' )
148 {
149 /* deal with data/control lines: 245 12 ........ */
150 char tag[4];
151 const char *datafield_start = line+6;
152 marker_ch = 0;
153 marker_skip = 0;
154
155 memcpy(tag, line, 3);
156 tag[3] = '\0';
157 if (line_len >= 8) /* control - or datafield ? */
158 {
159 if (*datafield_start == ' ')
160 datafield_start++; /* skip blank after indicator */
161
162 if (strchr("$_*", *datafield_start))
163 {
164 marker_ch = *datafield_start;
165 if (datafield_start[2] == ' ')
166 marker_skip = 1; /* subfields has blank before data */
167 }
168 }
169 if (!header_created)
170 {
171 const char *leader = "01000cam 2200265 i 4500";
172
173 yaz_marc_set_leader(mt, leader,
174 &indicator_length,
175 &identifier_length,
176 &base_address,
177 &length_data_entry,
178 &length_starting,
179 &length_implementation);
180 header_created = 1;
181 }
182
183 if (marker_ch == 0)
184 { /* control field */
185 yaz_marc_add_controlfield(mt, tag, line+4, strlen(line+4));
186 }
187 else
188 { /* data field */
189 const char *indicator = line+4;
190 int indicator_len = 2;
191 const char *cp = datafield_start;
192
193 yaz_marc_add_datafield(mt, tag, indicator, indicator_len);
194 for (;;)
195 {
196 const char *next;
197 size_t len;
198
199 assert(cp[0] == marker_ch);
200 cp++;
201 next = cp;
202 while ((next = strchr(next, marker_ch)))
203 {
204 if ((next[1] >= 'A' && next[1] <= 'Z')
205 ||(next[1] >= 'a' && next[1] <= 'z')
206 ||(next[1] >= '0' && next[1] <= '9'))
207 {
208 if (!marker_skip)
209 break;
210 else if (next[2] == ' ')
211 break;
212 }
213 next++;
214 }
215 len = strlen(cp);
216 if (next)
217 len = next - cp - marker_skip;
218
219 if (marker_skip)
220 {
221 /* remove ' ' after subfield marker */
222 char *cp_blank = strchr(cp, ' ');
223 if (cp_blank)
224 {
225 len--;
226 while (cp_blank != cp)
227 {
228 cp_blank[0] = cp_blank[-1];
229 cp_blank--;
230 }
231 cp++;
232 }
233 }
234 yaz_marc_add_subfield(mt, cp, len);
235 if (!next)
236 break;
237 cp = next;
238 }
239 }
240 }
241 else
242 {
243 yaz_marc_cprintf(mt, "Ignoring line: %s", line);
244 }
245 }
246 wrbuf_destroy(wrbuf_line);
247 if (!header_created)
248 return -1;
249 return 0;
250}
251
252/*
253 * Local variables:
254 * c-basic-offset: 4
255 * c-file-style: "Stroustrup"
256 * indent-tabs-mode: nil
257 * End:
258 * vim: shiftwidth=4 tabstop=8 expandtab
259 */
260
int atoi_n_check(const char *buf, int size, int *val)
like atoi_n but checks for proper formatting
Definition atoin.c:32
static int yaz_marc_line_gets(int(*getbyte)(void *client_data), void(*ungetbyte)(int b, void *client_data), void *client_data, WRBUF w)
int yaz_marc_read_line(yaz_marc_t mt, int(*getbyte)(void *client_data), void(*ungetbyte)(int b, void *client_data), void *client_data)
read MARC lineformat from stream
static int yaz_gets(int(*getbyte)(void *client_data), void(*ungetbyte)(int b, void *client_data), void *client_data, WRBUF w)
void yaz_marc_cprintf(yaz_marc_t mt, const char *fmt,...)
adds MARC annotation - printf interface
Definition marcdisp.c:188
void yaz_marc_add_subfield(yaz_marc_t mt, const char *code_data, size_t code_data_len)
adds subfield to MARC structure
Definition marcdisp.c:316
void yaz_marc_add_datafield(yaz_marc_t mt, const char *tag, const char *indicator, size_t indicator_len)
adds datafield to MARC structure using strings
Definition marcdisp.c:233
void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c, int *indicator_length, int *identifier_length, int *base_address, int *length_data_entry, int *length_starting, int *length_implementation)
sets leader, validates it, and returns important values
Definition marcdisp.c:356
void yaz_marc_add_controlfield(yaz_marc_t mt, const char *tag, const char *data, size_t data_len)
adds controlfield to MARC structure
Definition marcdisp.c:212
void yaz_marc_reset(yaz_marc_t mt)
clears memory and MARC record
Definition marcdisp.c:483
MARC conversion.
string buffer
Definition wrbuf.h:43
the internals of a yaz_marc_t handle
Definition marcdisp.c:86
void wrbuf_destroy(WRBUF b)
destroy WRBUF and its buffer
Definition wrbuf.c:38
const char * wrbuf_cstr(WRBUF b)
returns WRBUF content as C-string
Definition wrbuf.c:299
void wrbuf_rewind(WRBUF b)
empty WRBUF content (length of buffer set to 0)
Definition wrbuf.c:47
WRBUF wrbuf_alloc(void)
construct WRBUF
Definition wrbuf.c:25
void wrbuf_cut_right(WRBUF b, size_t no_to_remove)
cut size of WRBUF
Definition wrbuf.c:315
void wrbuf_puts(WRBUF b, const char *buf)
appends C-string to WRBUF
Definition wrbuf.c:89
Header for WRBUF (growing buffer)
#define wrbuf_putc(b, c)
Definition wrbuf.h:287
#define wrbuf_buf(b)
Definition wrbuf.h:270
#define wrbuf_len(b)
Definition wrbuf.h:269
Header for common YAZ utilities.