| /* Copyright (C) 2000-2004 Free Software Foundation, Inc. |
| This file is part of the GNU LIBICONV Library. |
| |
| The GNU LIBICONV Library is free software; you can redistribute it |
| and/or modify it under the terms of the GNU Library General Public |
| License as published by the Free Software Foundation; either version 2 |
| of the License, or (at your option) any later version. |
| |
| The GNU LIBICONV Library is distributed in the hope that it will be |
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Library General Public License for more details. |
| |
| You should have received a copy of the GNU Library General Public |
| License along with the GNU LIBICONV Library; see the file COPYING.LIB. |
| If not, write to the Free Software Foundation, Inc., 59 Temple Place - |
| Suite 330, Boston, MA 02111-1307, USA. */ |
| |
| #include "config.h" |
| #ifndef ICONV_CONST |
| # define ICONV_CONST const |
| #endif |
| |
| #include <stddef.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <iconv.h> |
| #include <errno.h> |
| #if HAVE_LOCALE_H |
| #include <locale.h> |
| #endif |
| #include <fcntl.h> |
| |
| /* Ensure that iconv_no_i18n does not depend on libintl. */ |
| #ifdef NO_I18N |
| # undef ENABLE_NLS |
| # undef ENABLE_RELOCATABLE |
| #endif |
| |
| #include "binary-io.h" |
| #include "progname.h" |
| #include "relocatable.h" |
| #include "gettext.h" |
| |
| #define _(str) gettext(str) |
| |
| static int discard_unconvertible = 0; |
| static int silent = 0; |
| |
| static void usage (int exitcode) |
| { |
| const char* helpstring1 = |
| _("Usage: iconv [-c] [-s] [-f fromcode] [-t tocode] [file ...]"); |
| const char* helpstring2 = |
| _("or: iconv -l"); |
| fprintf(exitcode ? stderr : stdout, "%s\n%s\n", helpstring1, helpstring2); |
| exit(exitcode); |
| } |
| |
| static void print_version (void) |
| { |
| printf("iconv (GNU libiconv %d.%d)\n", |
| _libiconv_version >> 8, _libiconv_version & 0xff); |
| printf("Copyright (C) %s Free Software Foundation, Inc.\n", "2000-2002"); |
| printf(_("\ |
| This is free software; see the source for copying conditions. There is NO\n\ |
| warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n")); |
| printf(_("Written by %s.\n"),"Bruno Haible"); |
| exit(0); |
| } |
| |
| static int print_one (unsigned int namescount, const char * const * names, |
| void* data) |
| { |
| unsigned int i; |
| (void)data; |
| for (i = 0; i < namescount; i++) { |
| if (i > 0) |
| putc(' ',stdout); |
| fputs(names[i],stdout); |
| } |
| putc('\n',stdout); |
| return 0; |
| } |
| |
| static int convert (iconv_t cd, FILE* infile, const char* infilename) |
| { |
| char inbuf[4096+4096]; |
| size_t inbufrest = 0; |
| char outbuf[4096]; |
| int status = 0; |
| |
| #if O_BINARY |
| SET_BINARY(fileno(infile)); |
| #endif |
| iconv(cd,NULL,NULL,NULL,NULL); |
| for (;;) { |
| size_t inbufsize = fread(inbuf+4096,1,4096,infile); |
| if (inbufsize == 0) { |
| if (inbufrest == 0) |
| break; |
| else { |
| if (!silent) |
| fprintf(stderr,_("iconv: %s: incomplete character or shift sequence\n"),infilename); |
| return 1; |
| } |
| } else { |
| const char* inptr = inbuf+4096-inbufrest; |
| size_t insize = inbufrest+inbufsize; |
| inbufrest = 0; |
| while (insize > 0) { |
| char* outptr = outbuf; |
| size_t outsize = sizeof(outbuf); |
| size_t res = iconv(cd,(ICONV_CONST char**)&inptr,&insize,&outptr,&outsize); |
| if (outptr != outbuf) { |
| int saved_errno = errno; |
| if (fwrite(outbuf,1,outptr-outbuf,stdout) < outptr-outbuf) |
| return 1; |
| errno = saved_errno; |
| } |
| if (res == (size_t)(-1)) { |
| if (errno == EILSEQ) { |
| if (discard_unconvertible == 1) { |
| int one = 1; |
| iconvctl(cd,ICONV_SET_DISCARD_ILSEQ,&one); |
| discard_unconvertible = 2; |
| status = 1; |
| } else { |
| if (!silent) |
| fprintf(stderr,_("iconv: %s: cannot convert\n"),infilename); |
| return 1; |
| } |
| } else if (errno == EINVAL) { |
| if (inbufsize == 0 || insize > 4096) { |
| if (!silent) |
| fprintf(stderr,_("iconv: %s: incomplete character or shift sequence\n"),infilename); |
| return 1; |
| } else { |
| inbufrest = insize; |
| if (insize > 0) { |
| /* Like memcpy(inbuf+4096-insize,inptr,insize), except that |
| we cannot use memcpy here, because source and destination |
| regions may overlap. */ |
| char* restptr = inbuf+4096-insize; |
| do { *restptr++ = *inptr++; } while (--insize > 0); |
| } |
| break; |
| } |
| } else if (errno != E2BIG) { |
| if (!silent) { |
| int saved_errno = errno; |
| fprintf(stderr,_("iconv: %s: "),infilename); |
| errno = saved_errno; |
| perror(""); |
| } |
| return 1; |
| } |
| } |
| } |
| } |
| } |
| { |
| char* outptr = outbuf; |
| size_t outsize = sizeof(outbuf); |
| size_t res = iconv(cd,NULL,NULL,&outptr,&outsize); |
| if (outptr != outbuf) { |
| int saved_errno = errno; |
| if (fwrite(outbuf,1,outptr-outbuf,stdout) < outptr-outbuf) |
| return 1; |
| errno = saved_errno; |
| } |
| if (res == (size_t)(-1)) { |
| if (errno == EILSEQ) { |
| if (discard_unconvertible == 1) { |
| int one = 1; |
| iconvctl(cd,ICONV_SET_DISCARD_ILSEQ,&one); |
| discard_unconvertible = 2; |
| status = 1; |
| } else { |
| if (!silent) |
| fprintf(stderr,_("iconv: %s: cannot convert\n"),infilename); |
| return 1; |
| } |
| } else if (errno == EINVAL) { |
| if (!silent) |
| fprintf(stderr,_("iconv: %s: incomplete character or shift sequence\n"),infilename); |
| return 1; |
| } else { |
| if (!silent) { |
| int saved_errno = errno; |
| fprintf(stderr,_("iconv: %s: "),infilename); |
| errno = saved_errno; |
| perror(""); |
| } |
| return 1; |
| } |
| } |
| } |
| if (ferror(infile)) { |
| fprintf(stderr,_("iconv: %s: I/O error\n"),infilename); |
| return 1; |
| } |
| return status; |
| } |
| |
| int main (int argc, char* argv[]) |
| { |
| const char* fromcode = NULL; |
| const char* tocode = NULL; |
| int do_list = 0; |
| iconv_t cd; |
| int i; |
| int status; |
| |
| set_program_name (argv[0]); |
| #if HAVE_SETLOCALE |
| /* Needed for the locale dependent encodings, "char" and "wchar_t", |
| and for gettext. */ |
| setlocale(LC_CTYPE,""); |
| #if ENABLE_NLS |
| /* Needed for gettext. */ |
| setlocale(LC_MESSAGES,""); |
| #endif |
| #endif |
| #if ENABLE_NLS |
| bindtextdomain("libiconv",relocate(LOCALEDIR)); |
| #endif |
| textdomain("libiconv"); |
| for (i = 1; i < argc;) { |
| if (!strcmp(argv[i],"-f")) { |
| if (i == argc-1) usage(1); |
| if (fromcode != NULL) usage(1); |
| fromcode = argv[i+1]; |
| i += 2; |
| continue; |
| } |
| if (!strcmp(argv[i],"-t")) { |
| if (i == argc-1) usage(1); |
| if (tocode != NULL) usage(1); |
| tocode = argv[i+1]; |
| i += 2; |
| continue; |
| } |
| if (!strcmp(argv[i],"-l")) { |
| do_list = 1; |
| i++; |
| continue; |
| } |
| if (!strcmp(argv[i],"--help")) { |
| usage(0); |
| } |
| if (!strcmp(argv[i],"--version")) { |
| print_version(); |
| } |
| #if O_BINARY |
| /* Backward compatibility with iconv <= 1.9.1. */ |
| if (!strcmp(argv[i],"--binary")) { |
| i++; |
| continue; |
| } |
| #endif |
| if (argv[i][0] == '-') { |
| const char *option = argv[i] + 1; |
| if (*option == '\0') |
| usage(1); |
| for (; *option; option++) |
| switch (*option) { |
| case 'c': discard_unconvertible = 1; break; |
| case 's': silent = 1; break; |
| default: usage(1); |
| } |
| i++; |
| continue; |
| } |
| break; |
| } |
| if (do_list) { |
| if (i != 2 || i != argc) |
| usage(1); |
| iconvlist(print_one,NULL); |
| status = 0; |
| } else { |
| #if O_BINARY |
| SET_BINARY(fileno(stdout)); |
| #endif |
| if (fromcode == NULL) |
| fromcode = "char"; |
| if (tocode == NULL) |
| tocode = "char"; |
| cd = iconv_open(tocode,fromcode); |
| if (cd == (iconv_t)(-1)) { |
| if (iconv_open("UCS-4",fromcode) == (iconv_t)(-1)) |
| fprintf(stderr,_("iconv: conversion from %s unsupported\n"),fromcode); |
| else if (iconv_open(tocode,"UCS-4") == (iconv_t)(-1)) |
| fprintf(stderr,_("iconv: conversion to %s unsupported\n"),tocode); |
| else |
| fprintf(stderr,_("iconv: conversion from %s to %s unsupported\n"),fromcode,tocode); |
| exit(1); |
| } |
| if (i == argc) |
| status = convert(cd,stdin,_("(stdin)")); |
| else { |
| status = 0; |
| for (; i < argc; i++) { |
| const char* infilename = argv[i]; |
| FILE* infile = fopen(infilename,"r"); |
| if (infile == NULL) { |
| int saved_errno = errno; |
| fprintf(stderr,_("iconv: %s: "),infilename); |
| errno = saved_errno; |
| perror(""); |
| status = 1; |
| } else { |
| status |= convert(cd,infile,infilename); |
| fclose(infile); |
| } |
| } |
| } |
| iconv_close(cd); |
| } |
| if (fflush(stdout) || ferror(stdout)) { |
| fprintf(stderr,_("iconv: I/O error\n")); |
| status = 1; |
| } |
| exit(status); |
| } |