/*- * Copyright (c)2007 Citrus Project, * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include static int silent = 0; typedef struct { iconv_t cd; size_t inbufsize, outbufsize; char *inbuf, *outbuf; } converter_t; static __inline void converter_init(converter_t *p, const char *from, const char *to) { p->inbufsize = p->outbufsize = BUFSIZ; p->inbuf = malloc(p->inbufsize); if (p->inbuf == NULL) errx(1, "can't malloc"); p->outbuf = malloc(p->outbufsize); if (p->outbuf == NULL) errx(1, "can't malloc"); p->cd = iconv_open(to, from); if (p->cd == (iconv_t)-1) errx(1, "can't iconv_open"); } static __inline void converter_uninit(converter_t *p) { free(p->inbuf); free(p->outbuf); iconv_close(p->cd); } static void converter_exec(converter_t *p, FILE *reader, FILE *writer) { int ch; size_t irreversible, nread, inbytes, outbytes, ret, nconv; char *in, *out; irreversible = (size_t)0; while ((nread = fread(p->inbuf, 1, p->inbufsize, reader)) > 0) { in = p->inbuf; inbytes = nread; while (inbytes > 0) { out = p->outbuf; outbytes = p->outbufsize; ret = iconv(p->cd, (const char **)&in, &inbytes, &out, &outbytes); nconv = p->outbufsize - outbytes; if (ret == (size_t)-1) { switch (errno) { case EINVAL: if (in != p->inbuf) memmove(p->inbuf, in, inbytes); p->inbufsize *= 2; in = realloc(p->inbuf, p->inbufsize); if (in == NULL) errx(1, "can't realloc"); p->inbuf = in; nread = fread(p->inbuf + inbytes, 1, p->inbufsize - inbytes, reader); if (nread == (size_t)0) errx(1, "unexpected eof"); inbytes += nread; break; case E2BIG: p->outbufsize *= 2; out = realloc(p->outbuf, p->outbufsize); if (out == NULL) errx(1, "can't realloc"); p->outbuf = out; break; default: errx(1, "can't iconv"); } } else { irreversible += ret; } if (nconv > 0) fwrite((const void*)p->outbuf, 1, nconv, writer); } } do { out = p->outbuf; outbytes = p->outbufsize; ret = iconv(p->cd, NULL, NULL, &out, &outbytes); nconv = p->outbufsize - outbytes; if (ret == (size_t)-1) { if (errno != E2BIG) errx(1, "can't iconv"); p->outbufsize *= 2; out = realloc(p->outbuf, p->outbufsize); if (out == NULL) errx(1, "can't realloc"); p->outbuf = out; } else { irreversible += ret; } if (nconv > 0) fwrite((const void *)p->outbuf, 1, nconv, writer); } while (ret == (size_t)-1); if (!silent && irreversible > 0) warnx("%zu irreversible character", irreversible); } int main(int argc, char *argv[]) { const char *from, *to; int ch; converter_t converter; FILE *fp; setlocale(LC_CTYPE, ""); from = to = nl_langinfo(CODESET); while ((ch = getopt(argc, argv, "f:t:s")) != -1) { switch (ch) { case 'f': from = (const char *)optarg; break; case 't': to = (const char *)optarg; break; case 's': silent = 1; break; default: fprintf(stderr, "usage: %s [-s] -f -t [file ...]\n", getprogname()); exit(1); } } argc -= optind; argv += optind; converter_init(&converter, from, to); if (argc < 1) converter_exec(&converter, stdin, stdout); while (argc-- > 0) { fp = fopen(*argv++, "r"); if (fp == NULL) errx(1, "can't fopen"); converter_exec(&converter, fp, stdout); fclose(fp); } converter_uninit(&converter); return 0; }