57de6e1f4a7671001117450341fd638763f8814d
[yaz-moved-to-github.git] / util / yaziconv.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) Index Data
3  * See the file LICENSE for details.
4  */
5
6 #if HAVE_CONFIG_H
7 #include <config.h>
8 #endif
9
10 #include <stdlib.h>
11 #include <errno.h>
12 #include <string.h>
13
14 #include <yaz/yaz-util.h>
15 #include <yaz/backtrace.h>
16
17 #define CHUNK_IN 64
18 #define CHUNK_OUT 64
19
20 void write_out(const char *b0, const char *b1)
21 {
22     size_t sz = b1 - b0;
23     if (sz)
24     {
25         if (fwrite(b0, 1, sz, stdout) != sz)
26         {
27             fprintf(stderr, "yaz-iconv: write failed\n");
28             exit(8);
29         }
30     }
31 }
32
33 void convert(FILE *inf, yaz_iconv_t cd, int verbose)
34 {
35     char inbuf0[CHUNK_IN], *inbuf = inbuf0;
36     char outbuf0[CHUNK_OUT], *outbuf = outbuf0;
37     size_t inbytesleft = CHUNK_IN;
38     size_t outbytesleft = CHUNK_OUT;
39     int mustread = 1;
40
41     while (1)
42     {
43         size_t r;
44         if (mustread)
45         {
46             r = fread(inbuf, 1, inbytesleft, inf);
47             if (inbytesleft != r)
48             {
49                 if (ferror(inf))
50                 {
51                     fprintf(stderr, "yaz-iconv: error reading file\n");
52                     exit(6);
53                 }
54                 if (r == 0)
55                 {
56                     write_out(outbuf0, outbuf);
57                     outbuf = outbuf0;
58                     outbytesleft = CHUNK_OUT;
59                     r = yaz_iconv(cd, 0, 0, &outbuf, &outbytesleft);
60                     write_out(outbuf0, outbuf);
61                     break;
62                 }
63                 inbytesleft = r;
64             }
65         }
66         if (verbose > 1)
67         {
68             fprintf(stderr, "yaz_iconv: inbytesleft=%ld outbytesleft=%ld\n",
69                     (long) inbytesleft, (long) outbytesleft);
70
71         }
72         r = yaz_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
73         if (r == (size_t)(-1))
74         {
75             int e = yaz_iconv_error(cd);
76             if (e == YAZ_ICONV_EILSEQ)
77             {
78                 fprintf(stderr, "invalid sequence\n");
79                 return ;
80             }
81             else if (e == YAZ_ICONV_EINVAL) /* incomplete input */
82             {
83                 size_t i;
84                 for (i = 0; i<inbytesleft; i++)
85                     inbuf0[i] = inbuf[i];
86
87                 r = fread(inbuf0 + i, 1, CHUNK_IN - i, inf);
88                 if (r != CHUNK_IN - i)
89                 {
90                     if (ferror(inf))
91                     {
92                         fprintf(stderr, "yaz-iconv: error reading file\n");
93                         exit(6);
94                     }
95                 }
96                 if (r == 0)
97                 {
98                     fprintf(stderr, "invalid sequence due to missing input\n");
99                     return ;
100                 }
101                 inbytesleft += r;
102                 inbuf = inbuf0;
103                 mustread = 0;
104             }
105             else if (e == YAZ_ICONV_E2BIG) /* no more output space */
106             {
107                 write_out(outbuf0, outbuf);
108                 outbuf = outbuf0;
109                 outbytesleft = CHUNK_OUT;
110                 mustread = 0;
111             }
112             else
113             {
114                 fprintf(stderr, "yaz-iconv: unknown error\n");
115                 exit(7);
116             }
117         }
118         else
119         {
120             inbuf = inbuf0;
121             inbytesleft = CHUNK_IN;
122
123             write_out(outbuf0, outbuf);
124             outbuf = outbuf0;
125             outbytesleft = CHUNK_OUT;
126
127             mustread = 1;
128         }
129     }
130 }
131
132 int main(int argc, char **argv)
133 {
134     int ret;
135     int verbose = 0;
136     char *from = 0;
137     char *to = 0;
138     char *arg;
139     yaz_iconv_t cd;
140     FILE *inf = stdin;
141
142     yaz_enable_panic_backtrace(*argv);
143     while ((ret = options("vf:t:", argv, argc, &arg)) != -2)
144     {
145         switch (ret)
146         {
147         case 0:
148             inf = fopen(arg, "rb");
149             if (!inf)
150             {
151                 fprintf(stderr, "yaz-iconv: cannot open %s", arg);
152                 exit(2);
153             }
154             break;
155         case 'f':
156             from = arg;
157             break;
158         case 't':
159             to = arg;
160             break;
161         case 'v':
162             verbose++;
163             break;
164         default:
165             fprintf(stderr, "yaz-iconv: Usage\n"
166                     "yaziconv -f encoding -t encoding [-v] [file]\n");
167             exit(1);
168         }
169     }
170     if (!to)
171     {
172         fprintf(stderr, "yaz-iconv: -t encoding missing\n");
173         exit(3);
174     }
175     if (!from)
176     {
177         fprintf(stderr, "yaz-iconv: -f encoding missing\n");
178         exit(4);
179     }
180     cd = yaz_iconv_open(to, from);
181     if (!cd)
182     {
183         fprintf(stderr, "yaz-iconv: unsupported encoding\n");
184         exit(5);
185     }
186     else
187     {
188         if (verbose)
189         {
190             fprintf(stderr, "yaz-iconv: using %s\n",
191                     yaz_iconv_isbuiltin(cd) ? "YAZ" : "iconv");
192         }
193     }
194     convert(inf, cd, verbose);
195     yaz_iconv_close(cd);
196     return 0;
197 }
198 /*
199  * Local variables:
200  * c-basic-offset: 4
201  * c-file-style: "Stroustrup"
202  * indent-tabs-mode: nil
203  * End:
204  * vim: shiftwidth=4 tabstop=8 expandtab
205  */
206