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