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