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