Decouple the mbtowc and wctomb calling conventions.
[libiconv.git] / src / iconv.c
bloba937b813d7acd2ade039dbcdfd225a7b05647966
1 /* Copyright (C) 2000-2001 Free Software Foundation, Inc.
2 This file is part of the GNU LIBICONV Library.
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.
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.
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. */
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>
31 /* For systems that distinguish between text and binary I/O.
32 O_BINARY is usually declared in <fcntl.h>. */
33 #if !defined O_BINARY && defined _O_BINARY
34 /* For MSC-compatible compilers. */
35 # define O_BINARY _O_BINARY
36 # define O_TEXT _O_TEXT
37 #endif
38 #ifdef __BEOS__
39 /* BeOS 5 has O_BINARY and O_TEXT, but they have no effect. */
40 # undef O_BINARY
41 # undef O_TEXT
42 #endif
43 #if O_BINARY
44 # if !(defined(__EMX__) || defined(__DJGPP__))
45 # define setmode _setmode
46 # define fileno _fileno
47 # endif
48 # ifdef __DJGPP__
49 # include <io.h> /* declares setmode() */
50 # include <unistd.h> /* declares isatty() */
51 # /* Avoid putting stdin/stdout in binary mode if it is connected to the
52 # console, because that would make it impossible for the user to
53 # interrupt the program through Ctrl-C or Ctrl-Break. */
54 # define SET_BINARY(fd) (!isatty(fd) ? (setmode(fd,O_BINARY), 0) : 0)
55 # else
56 # define SET_BINARY(fd) setmode(fd,O_BINARY)
57 # endif
58 #endif
60 #if O_BINARY
61 static int force_binary = 0;
62 #endif
64 static void usage (int exitcode)
66 const char* helpstring =
67 #if O_BINARY
68 "Usage: iconv [--binary] [-f fromcode] [-t tocode] [file ...]\n";
69 #else
70 "Usage: iconv [-f fromcode] [-t tocode] [file ...]\n";
71 #endif
72 fprintf(exitcode ? stderr : stdout, helpstring);
73 exit(exitcode);
76 static void print_version (void)
78 printf("iconv (GNU libiconv %d.%d)\n",
79 _libiconv_version >> 8, _libiconv_version & 0xff);
80 printf("\
81 Copyright (C) 2000-2001 Free Software Foundation, Inc.\n\
82 This is free software; see the source for copying conditions. There is NO\n\
83 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
84 Written by Bruno Haible.\n");
85 exit(0);
88 static int convert (iconv_t cd, FILE* infile, const char* infilename)
90 char inbuf[4096+4096];
91 size_t inbufrest = 0;
92 char outbuf[4096];
94 #if O_BINARY
95 if (force_binary)
96 SET_BINARY(fileno(infile));
97 #endif
98 iconv(cd,NULL,NULL,NULL,NULL);
99 for (;;) {
100 size_t inbufsize = fread(inbuf+4096,1,4096,infile);
101 if (inbufsize == 0) {
102 if (inbufrest == 0)
103 break;
104 else {
105 fprintf(stderr,"iconv: %s: incomplete character or shift sequence\n",infilename);
106 return 1;
108 } else {
109 const char* inptr = inbuf+4096-inbufrest;
110 size_t insize = inbufrest+inbufsize;
111 inbufrest = 0;
112 while (insize > 0) {
113 char* outptr = outbuf;
114 size_t outsize = sizeof(outbuf);
115 size_t res = iconv(cd,(ICONV_CONST char**)&inptr,&insize,&outptr,&outsize);
116 if (outptr != outbuf) {
117 int saved_errno = errno;
118 if (fwrite(outbuf,1,outptr-outbuf,stdout) < outptr-outbuf)
119 return 1;
120 errno = saved_errno;
122 if (res == (size_t)(-1)) {
123 if (errno == EILSEQ) {
124 fprintf(stderr,"iconv: %s: cannot convert\n",infilename);
125 return 1;
126 } else if (errno == EINVAL) {
127 if (inbufsize == 0 || insize > 4096) {
128 fprintf(stderr,"iconv: %s: incomplete character or shift sequence\n",infilename);
129 return 1;
130 } else {
131 inbufrest = insize;
132 if (insize > 0) {
133 /* Like memcpy(inbuf+4096-insize,inptr,insize), except that
134 we cannot use memcpy here, because source and destination
135 regions may overlap. */
136 char* restptr = inbuf+4096-insize;
137 do { *restptr++ = *inptr++; } while (--insize > 0);
139 break;
141 } else if (errno != E2BIG) {
142 int saved_errno = errno;
143 fprintf(stderr,"iconv: %s: ",infilename);
144 errno = saved_errno;
145 perror("");
146 return 1;
153 char* outptr = outbuf;
154 size_t outsize = sizeof(outbuf);
155 size_t res = iconv(cd,NULL,NULL,&outptr,&outsize);
156 if (outptr != outbuf) {
157 int saved_errno = errno;
158 if (fwrite(outbuf,1,outptr-outbuf,stdout) < outptr-outbuf)
159 return 1;
160 errno = saved_errno;
162 if (res == (size_t)(-1)) {
163 if (errno == EILSEQ) {
164 fprintf(stderr,"iconv: %s: cannot convert\n",infilename);
165 return 1;
166 } else if (errno == EINVAL) {
167 fprintf(stderr,"iconv: %s: incomplete character or shift sequence\n",infilename);
168 return 1;
169 } else {
170 int saved_errno = errno;
171 fprintf(stderr,"iconv: %s: ",infilename);
172 errno = saved_errno;
173 perror("");
174 return 1;
178 if (ferror(infile)) {
179 fprintf(stderr,"iconv: %s: I/O error\n",infilename);
180 return 1;
182 return 0;
185 int main (int argc, char* argv[])
187 const char* fromcode = NULL;
188 const char* tocode = NULL;
189 iconv_t cd;
190 int i;
191 int status;
193 #if HAVE_SETLOCALE
194 /* Needed for the locale dependent encodings, "char" and "wchar_t". */
195 setlocale(LC_CTYPE,"");
196 #endif
197 for (i = 1; i < argc;) {
198 if (!strcmp(argv[i],"-f")) {
199 if (i == argc-1) usage(1);
200 if (fromcode != NULL) usage(1);
201 fromcode = argv[i+1];
202 i += 2;
203 continue;
205 if (!strcmp(argv[i],"-t")) {
206 if (i == argc-1) usage(1);
207 if (tocode != NULL) usage(1);
208 tocode = argv[i+1];
209 i += 2;
210 continue;
212 if (!strcmp(argv[i],"--help")) {
213 usage(0);
215 if (!strcmp(argv[i],"--version")) {
216 print_version();
218 #if O_BINARY
219 if (!strcmp(argv[i],"--binary")) {
220 force_binary = 1;
221 i++;
222 continue;
224 #endif
225 if (argv[i][0] == '-')
226 usage(1);
227 break;
229 #if O_BINARY
230 if (force_binary)
231 SET_BINARY(fileno(stdout));
232 #endif
233 if (fromcode == NULL)
234 fromcode = "char";
235 if (tocode == NULL)
236 tocode = "char";
237 cd = iconv_open(tocode,fromcode);
238 if (cd == (iconv_t)(-1)) {
239 if (iconv_open("UCS-4",fromcode) == (iconv_t)(-1))
240 fprintf(stderr,"iconv: conversion from %s unsupported\n",fromcode);
241 else if (iconv_open(tocode,"UCS-4") == (iconv_t)(-1))
242 fprintf(stderr,"iconv: conversion to %s unsupported\n",tocode);
243 else
244 fprintf(stderr,"iconv: conversion from %s to %s unsupported\n",fromcode,tocode);
245 exit(1);
247 if (i == argc)
248 status = convert(cd,stdin,"(stdin)");
249 else {
250 status = 0;
251 for (; i < argc; i++) {
252 const char* infilename = argv[i];
253 FILE* infile = fopen(infilename,"r");
254 if (infile == NULL) {
255 int saved_errno = errno;
256 fprintf(stderr,"iconv: %s: ",infilename);
257 errno = saved_errno;
258 perror("");
259 status = 1;
260 } else {
261 status |= convert(cd,infile,infilename);
262 fclose(infile);
266 iconv_close(cd);
267 if (ferror(stdout)) {
268 fprintf(stderr,"iconv: I/O error\n");
269 status = 1;
271 exit(status);