Initial revision
[TestXSLT.git] / libiconv / src / iconv.c
1 /* Copyright (C) 2000-2002 Free Software Foundation, Inc.
2    This file is part of the GNU LIBICONV Library.
3
4    The GNU LIBICONV Library is free software; you can redistribute it
5    and/or modify it under the terms of the GNU Library General Public
6    License as published by the Free Software Foundation; either version 2
7    of the License, or (at your option) any later version.
8
9    The GNU LIBICONV Library is distributed in the hope that it will be
10    useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13
14    You should have received a copy of the GNU Library General Public
15    License along with the GNU LIBICONV Library; see the file COPYING.LIB.
16    If not, write to the Free Software Foundation, Inc., 59 Temple Place -
17    Suite 330, Boston, MA 02111-1307, USA.  */
18
19 #include "config.h"
20 #include <stddef.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <iconv.h>
25 #include <errno.h>
26 #if HAVE_LOCALE_H
27 #include <locale.h>
28 #endif
29 #include <fcntl.h>
30
31 #ifdef NO_I18N
32 # undef ENABLE_NLS
33 #endif
34 #include "gettext.h"
35
36 #define _(str) gettext(str)
37
38 /* For systems that distinguish between text and binary I/O.
39    O_BINARY is usually declared in <fcntl.h>. */
40 #if !defined O_BINARY && defined _O_BINARY
41   /* For MSC-compatible compilers.  */
42 # define O_BINARY _O_BINARY
43 # define O_TEXT _O_TEXT
44 #endif
45 #ifdef __BEOS__
46   /* BeOS 5 has O_BINARY and O_TEXT, but they have no effect.  */
47 # undef O_BINARY
48 # undef O_TEXT
49 #endif
50 #if O_BINARY
51 # if !(defined(__EMX__) || defined(__DJGPP__))
52 #  define setmode _setmode
53 #  define fileno _fileno
54 # endif
55 # ifdef __DJGPP__
56 #  include <io.h> /* declares setmode() */
57 #  include <unistd.h> /* declares isatty() */
58 #  /* Avoid putting stdin/stdout in binary mode if it is connected to the
59 #     console, because that would make it impossible for the user to
60 #     interrupt the program through Ctrl-C or Ctrl-Break.  */
61 #  define SET_BINARY(fd) (!isatty(fd) ? (setmode(fd,O_BINARY), 0) : 0)
62 # else
63 #  define SET_BINARY(fd) setmode(fd,O_BINARY)
64 # endif
65 #endif
66
67 #if O_BINARY
68   static int force_binary = 0;
69 #endif
70
71 static int discard_unconvertible = 0;
72 static int silent = 0;
73
74 static void usage (int exitcode)
75 {
76   const char* helpstring1 =
77 #if O_BINARY
78     _("Usage: iconv [--binary] [-c] [-s] [-f fromcode] [-t tocode] [file ...]");
79 #else
80     _("Usage: iconv [-c] [-s] [-f fromcode] [-t tocode] [file ...]");
81 #endif
82   const char* helpstring2 =
83     _("or:    iconv -l");
84   fprintf(exitcode ? stderr : stdout, "%s\n%s\n", helpstring1, helpstring2);
85   exit(exitcode);
86 }
87
88 static void print_version (void)
89 {
90   printf("iconv (GNU libiconv %d.%d)\n",
91          _libiconv_version >> 8, _libiconv_version & 0xff);
92   printf("Copyright (C) %s Free Software Foundation, Inc.\n", "2000-2002");
93   printf(_("\
94 This is free software; see the source for copying conditions.  There is NO\n\
95 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"));
96   printf(_("Written by %s.\n"),"Bruno Haible");
97   exit(0);
98 }
99
100 static int print_one (unsigned int namescount, const char * const * names,
101                       void* data)
102 {
103   unsigned int i;
104   (void)data;
105   for (i = 0; i < namescount; i++) {
106     if (i > 0)
107       putc(' ',stdout);
108     fputs(names[i],stdout);
109   }
110   putc('\n',stdout);
111   return 0;
112 }
113
114 static int convert (iconv_t cd, FILE* infile, const char* infilename)
115 {
116   char inbuf[4096+4096];
117   size_t inbufrest = 0;
118   char outbuf[4096];
119   int status = 0;
120
121 #if O_BINARY
122   if (force_binary)
123     SET_BINARY(fileno(infile));
124 #endif
125   iconv(cd,NULL,NULL,NULL,NULL);
126   for (;;) {
127     size_t inbufsize = fread(inbuf+4096,1,4096,infile);
128     if (inbufsize == 0) {
129       if (inbufrest == 0)
130         break;
131       else {
132         if (!silent)
133           fprintf(stderr,_("iconv: %s: incomplete character or shift sequence\n"),infilename);
134         return 1;
135       }
136     } else {
137       const char* inptr = inbuf+4096-inbufrest;
138       size_t insize = inbufrest+inbufsize;
139       inbufrest = 0;
140       while (insize > 0) {
141         char* outptr = outbuf;
142         size_t outsize = sizeof(outbuf);
143         size_t res = iconv(cd,(ICONV_CONST char**)&inptr,&insize,&outptr,&outsize);
144         if (outptr != outbuf) {
145           int saved_errno = errno;
146           if (fwrite(outbuf,1,outptr-outbuf,stdout) < outptr-outbuf)
147             return 1;
148           errno = saved_errno;
149         }
150         if (res == (size_t)(-1)) {
151           if (errno == EILSEQ) {
152             if (discard_unconvertible == 1) {
153               int one = 1;
154               iconvctl(cd,ICONV_SET_DISCARD_ILSEQ,&one);
155               discard_unconvertible = 2;
156               status = 1;
157             } else {
158               if (!silent)
159                 fprintf(stderr,_("iconv: %s: cannot convert\n"),infilename);
160               return 1;
161             }
162           } else if (errno == EINVAL) {
163             if (inbufsize == 0 || insize > 4096) {
164               if (!silent)
165                 fprintf(stderr,_("iconv: %s: incomplete character or shift sequence\n"),infilename);
166               return 1;
167             } else {
168               inbufrest = insize;
169               if (insize > 0) {
170                 /* Like memcpy(inbuf+4096-insize,inptr,insize), except that
171                    we cannot use memcpy here, because source and destination
172                    regions may overlap. */
173                 char* restptr = inbuf+4096-insize;
174                 do { *restptr++ = *inptr++; } while (--insize > 0);
175               }
176               break;
177             }
178           } else if (errno != E2BIG) {
179             if (!silent) {
180               int saved_errno = errno;
181               fprintf(stderr,_("iconv: %s: "),infilename);
182               errno = saved_errno;
183               perror("");
184             }
185             return 1;
186           }
187         }
188       }
189     }
190   }
191   {
192     char* outptr = outbuf;
193     size_t outsize = sizeof(outbuf);
194     size_t res = iconv(cd,NULL,NULL,&outptr,&outsize);
195     if (outptr != outbuf) {
196       int saved_errno = errno;
197       if (fwrite(outbuf,1,outptr-outbuf,stdout) < outptr-outbuf)
198         return 1;
199       errno = saved_errno;
200     }
201     if (res == (size_t)(-1)) {
202       if (errno == EILSEQ) {
203         if (discard_unconvertible == 1) {
204           int one = 1;
205           iconvctl(cd,ICONV_SET_DISCARD_ILSEQ,&one);
206           discard_unconvertible = 2;
207           status = 1;
208         } else {
209           if (!silent)
210             fprintf(stderr,_("iconv: %s: cannot convert\n"),infilename);
211           return 1;
212         }
213       } else if (errno == EINVAL) {
214         if (!silent)
215           fprintf(stderr,_("iconv: %s: incomplete character or shift sequence\n"),infilename);
216         return 1;
217       } else {
218         if (!silent) {
219           int saved_errno = errno;
220           fprintf(stderr,_("iconv: %s: "),infilename);
221           errno = saved_errno;
222           perror("");
223         }
224         return 1;
225       }
226     }
227   }
228   if (ferror(infile)) {
229     fprintf(stderr,_("iconv: %s: I/O error\n"),infilename);
230     return 1;
231   }
232   return status;
233 }
234
235 int main (int argc, char* argv[])
236 {
237   const char* fromcode = NULL;
238   const char* tocode = NULL;
239   int do_list = 0;
240   iconv_t cd;
241   int i;
242   int status;
243
244 #if HAVE_SETLOCALE
245   /* Needed for the locale dependent encodings, "char" and "wchar_t",
246      and for gettext. */
247   setlocale(LC_CTYPE,"");
248 #if ENABLE_NLS
249   /* Needed for gettext. */
250   setlocale(LC_MESSAGES,"");
251 #endif
252 #endif
253   bindtextdomain("libiconv",LOCALEDIR);
254   textdomain("libiconv");
255   for (i = 1; i < argc;) {
256     if (!strcmp(argv[i],"-f")) {
257       if (i == argc-1) usage(1);
258       if (fromcode != NULL) usage(1);
259       fromcode = argv[i+1];
260       i += 2;
261       continue;
262     }
263     if (!strcmp(argv[i],"-t")) {
264       if (i == argc-1) usage(1);
265       if (tocode != NULL) usage(1);
266       tocode = argv[i+1];
267       i += 2;
268       continue;
269     }
270     if (!strcmp(argv[i],"-l")) {
271       do_list = 1;
272       i++;
273       continue;
274     }
275     if (!strcmp(argv[i],"--help")) {
276       usage(0);
277     }
278     if (!strcmp(argv[i],"--version")) {
279       print_version();
280     }
281 #if O_BINARY
282     if (!strcmp(argv[i],"--binary")) {
283       force_binary = 1;
284       i++;
285       continue;
286     }
287 #endif
288     if (argv[i][0] == '-') {
289       const char *option = argv[i] + 1;
290       if (*option == '\0')
291         usage(1);
292       for (; *option; option++)
293         switch (*option) {
294           case 'c': discard_unconvertible = 1; break;
295           case 's': silent = 1; break;
296           default: usage(1);
297         }
298       i++;
299       continue;
300     }
301     break;
302   }
303   if (do_list) {
304     if (i != 2 || i != argc)
305       usage(1);
306     iconvlist(print_one,NULL);
307     status = 0;
308   } else {
309 #if O_BINARY
310     if (force_binary)
311       SET_BINARY(fileno(stdout));
312 #endif
313     if (fromcode == NULL)
314       fromcode = "char";
315     if (tocode == NULL)
316       tocode = "char";
317     cd = iconv_open(tocode,fromcode);
318     if (cd == (iconv_t)(-1)) {
319       if (iconv_open("UCS-4",fromcode) == (iconv_t)(-1))
320         fprintf(stderr,_("iconv: conversion from %s unsupported\n"),fromcode);
321       else if (iconv_open(tocode,"UCS-4") == (iconv_t)(-1))
322         fprintf(stderr,_("iconv: conversion to %s unsupported\n"),tocode);
323       else
324         fprintf(stderr,_("iconv: conversion from %s to %s unsupported\n"),fromcode,tocode);
325       exit(1);
326     }
327     if (i == argc)
328       status = convert(cd,stdin,_("(stdin)"));
329     else {
330       status = 0;
331       for (; i < argc; i++) {
332         const char* infilename = argv[i];
333         FILE* infile = fopen(infilename,"r");
334         if (infile == NULL) {
335           int saved_errno = errno;
336           fprintf(stderr,_("iconv: %s: "),infilename);
337           errno = saved_errno;
338           perror("");
339           status = 1;
340         } else {
341           status |= convert(cd,infile,infilename);
342           fclose(infile);
343         }
344       }
345     }
346     iconv_close(cd);
347   }
348   if (ferror(stdout)) {
349     fprintf(stderr,_("iconv: I/O error\n"));
350     status = 1;
351   }
352   exit(status);
353 }