040a51b68dc80d623088182eab42ccdf77160124
[yaz-moved-to-github.git] / util / marcdump.c
1 /*
2  * Copyright (C) 1995-2006, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: marcdump.c,v 1.44 2006-12-07 11:08:05 adam Exp $
6  */
7
8 #define _FILE_OFFSET_BITS 64
9
10 #if HAVE_CONFIG_H
11 #include <config.h>
12 #endif
13
14 #if YAZ_HAVE_XML2
15 #include <libxml/parser.h>
16 #include <libxml/tree.h>
17
18 #include <libxml/xpath.h>
19 #include <libxml/xpathInternals.h>
20
21 #endif
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <assert.h>
28
29 #if HAVE_LOCALE_H
30 #include <locale.h>
31 #endif
32 #if HAVE_LANGINFO_H
33 #include <langinfo.h>
34 #endif
35
36 #include <yaz/marcdisp.h>
37 #include <yaz/yaz-util.h>
38 #include <yaz/xmalloc.h>
39 #include <yaz/options.h>
40
41 #ifndef SEEK_SET
42 #define SEEK_SET 0
43 #endif
44 #ifndef SEEK_END
45 #define SEEK_END 2
46 #endif
47
48
49 static char *prog;
50
51 static void usage(const char *prog)
52 {
53     fprintf (stderr, "Usage: %s [-c cfile] [-f from] [-t to] [-x] [-X] [-e] "
54              "[-I] [-n] [-l pos=value] [-v] [-C chunk] [-s splitfname] file...\n",
55              prog);
56
57
58 #if YAZ_HAVE_XML2
59 static void marcdump_read_xml(yaz_marc_t mt, const char *fname)
60 {
61     xmlNodePtr ptr;
62     xmlDocPtr doc = xmlParseFile(fname);
63     if (!doc)
64         return;
65
66     ptr = xmlDocGetRootElement(doc);
67     if (ptr)
68     {
69         int r;
70         WRBUF wrbuf = wrbuf_alloc();
71         r = yaz_marc_read_xml(mt, ptr);
72         if (r)
73             fprintf(stderr, "yaz_marc_read_xml failed\n");
74         else
75         {
76             yaz_marc_write_mode(mt, wrbuf);
77             
78             fputs(wrbuf_buf(wrbuf), stdout);
79         }
80         wrbuf_free(wrbuf, 1);
81     }
82     xmlFreeDoc(doc);
83 }
84 #endif
85
86 static void dump(const char *fname, const char *from, const char *to,
87                  int read_xml, int xml,
88                  int print_offset, const char *split_fname, int split_chunk,
89                  int verbose, FILE *cfile, const char *leader_spec)
90 {
91     yaz_marc_t mt = yaz_marc_create();
92     yaz_iconv_t cd = 0;
93
94     if (yaz_marc_leader_spec(mt, leader_spec))
95     {
96         fprintf(stderr, "bad leader spec: %s\n", leader_spec);
97         yaz_marc_destroy(mt);
98         exit(2);
99     }
100     if (from && to)
101     {
102         cd = yaz_iconv_open(to, from);
103         if (!cd)
104         {
105             fprintf(stderr, "conversion from %s to %s "
106                     "unsupported\n", from, to);
107             yaz_marc_destroy(mt);
108             exit(2);
109         }
110         yaz_marc_iconv(mt, cd);
111     }
112     yaz_marc_xml(mt, xml);
113     yaz_marc_debug(mt, verbose);
114
115     if (read_xml)
116     {
117 #if YAZ_HAVE_XML2
118         marcdump_read_xml(mt, fname);
119 #else
120         return;
121 #endif
122     }
123     else
124     {
125         FILE *inf = fopen(fname, "rb");
126         int num = 1;
127         int marc_no = 0;
128         int split_file_no = -1;
129         if (!inf)
130         {
131             fprintf (stderr, "%s: cannot open %s:%s\n",
132                      prog, fname, strerror (errno));
133             exit(1);
134         }
135         if (cfile)
136             fprintf (cfile, "char *marc_records[] = {\n");
137         for(;; marc_no++)
138         {
139             char *result = 0;
140             size_t len;
141             size_t rlen;
142             int len_result;
143             size_t r;
144             char buf[100001];
145             
146             r = fread (buf, 1, 5, inf);
147             if (r < 5)
148             {
149                 if (r && print_offset && verbose)
150                     printf ("<!-- Extra %ld bytes at end of file -->\n",
151                             (long) r);
152                 break;
153             }
154             while (*buf < '0' || *buf > '9')
155             {
156                 int i;
157                 long off = ftell(inf) - 5;
158                 if (verbose || print_offset)
159                     printf("<!-- Skipping bad byte %d (0x%02X) at offset "
160                            "%ld (0x%lx) -->\n", 
161                            *buf & 0xff, *buf & 0xff,
162                            off, off);
163                 for (i = 0; i<4; i++)
164                     buf[i] = buf[i+1];
165                 r = fread(buf+4, 1, 1, inf);
166                 if (r < 1)
167                     break;
168             }
169             if (r < 1)
170             {
171                 if (verbose || print_offset)
172                     printf ("<!-- End of file with data -->\n");
173                 break;
174             }
175             if (print_offset)
176             {
177                 long off = ftell(inf) - 5;
178                 printf ("<!-- Record %d offset %ld (0x%lx) -->\n",
179                         num, off, off);
180             }
181             len = atoi_n(buf, 5);
182             if (len < 25 || len > 100000)
183             {
184                 long off = ftell(inf) - 5;
185                 printf("Bad Length %ld read at offset %ld (%lx)\n",
186                        (long)len, (long) off, (long) off);
187                 break;
188             }
189             rlen = len - 5;
190             r = fread (buf + 5, 1, rlen, inf);
191             if (r < rlen)
192                 break;
193             if (split_fname)
194             {
195                 char fname[256];
196                 const char *mode = 0;
197                 FILE *sf;
198                 if ((marc_no % split_chunk) == 0)
199                 {
200                     mode = "wb";
201                     split_file_no++;
202                 }
203                 else
204                     mode = "ab";
205                 sprintf(fname, "%.200s%07d", split_fname, split_file_no);
206                 sf = fopen(fname, mode);
207                 if (!sf)
208                 {
209                     fprintf(stderr, "Could not open %s\n", fname);
210                     split_fname = 0;
211                 }
212                 else
213                 {
214                     if (fwrite(buf, 1, len, sf) != len)
215                     {
216                         fprintf(stderr, "Could write content to %s\n",
217                                 fname);
218                         split_fname = 0;
219                     }
220                     fclose(sf);
221                 }
222             }
223             len_result = (int) rlen;
224             r = yaz_marc_decode_buf(mt, buf, -1, &result, &len_result);
225             if (r > 0 && result)
226             {
227                 fwrite (result, len_result, 1, stdout);
228             }
229             if (r > 0 && cfile)
230             {
231                 char *p = buf;
232                 size_t i;
233                 if (marc_no)
234                     fprintf (cfile, ",");
235                 fprintf (cfile, "\n");
236                 for (i = 0; i < r; i++)
237                 {
238                     if ((i & 15) == 0)
239                         fprintf (cfile, "  \"");
240                     fprintf (cfile, "\\x%02X", p[i] & 255);
241                     
242                     if (i < r - 1 && (i & 15) == 15)
243                         fprintf (cfile, "\"\n");
244                     
245                 }
246                 fprintf (cfile, "\"\n");
247             }
248             num++;
249             if (verbose)
250                 printf("\n");
251         }
252         if (cfile)
253             fprintf (cfile, "};\n");
254         fclose(inf);
255     }
256     if (cd)
257         yaz_iconv_close(cd);
258     yaz_marc_destroy(mt);
259 }
260
261 int main (int argc, char **argv)
262 {
263     int r;
264     int print_offset = 0;
265     char *arg;
266     int verbose = 0;
267     int no = 0;
268     int xml = 0;
269     FILE *cfile = 0;
270     char *from = 0, *to = 0;
271     int read_xml = 0;
272     int split_chunk = 1;
273     const char *split_fname = 0;
274     const char *leader_spec = 0;
275     
276 #if HAVE_LOCALE_H
277     setlocale(LC_CTYPE, "");
278 #endif
279 #if HAVE_LANGINFO_H
280 #ifdef CODESET
281     to = nl_langinfo(CODESET);
282 #endif
283 #endif
284
285     prog = *argv;
286     while ((r = options("C:npvc:xOeXIf:t:s:l:", argv, argc, &arg)) != -2)
287     {
288         no++;
289         switch (r)
290         {
291         case 'l':
292             leader_spec = arg;
293             break;
294         case 'f':
295             from = arg;
296             break;
297         case 't':
298             to = arg;
299             break;
300         case 'c':
301             if (cfile)
302                 fclose (cfile);
303             cfile = fopen(arg, "w");
304             break;
305         case 'x':
306 #if YAZ_HAVE_XML2
307             read_xml = 1;
308 #else
309             fprintf(stderr, "%s: -x not supported."
310                     " YAZ not compiled with Libxml2 support\n", prog);
311             exit(3);
312 #endif
313             break;
314         case 'O':
315             fprintf(stderr, "%s: OAI MARC no longer supported."
316                     " Use MARCXML instead.\n", prog);
317             exit(1);
318             break;
319         case 'e':
320             xml = YAZ_MARC_XCHANGE;
321             break;
322         case 'X':
323             xml = YAZ_MARC_MARCXML;
324             break;
325         case 'I':
326             xml = YAZ_MARC_ISO2709;
327             break;
328         case 'n':
329             xml = YAZ_MARC_CHECK;
330             break;
331         case 'p':
332             print_offset = 1;
333             break;
334         case 's':
335             split_fname = arg;
336             break;
337         case 'C':
338             split_chunk = atoi(arg);
339             break;
340         case 0:
341             dump(arg, from, to, read_xml, xml,
342                  print_offset, split_fname, split_chunk,
343                  verbose, cfile, leader_spec);
344             break;
345         case 'v':
346             verbose++;
347             break;
348         default:
349             usage(prog);
350             exit (1);
351         }
352     }
353     if (cfile)
354         fclose (cfile);
355     if (!no)
356     {
357         usage(prog);
358         exit (1);
359     }
360     exit (0);
361 }
362 /*
363  * Local variables:
364  * c-basic-offset: 4
365  * indent-tabs-mode: nil
366  * End:
367  * vim: shiftwidth=4 tabstop=8 expandtab
368  */
369