From 02d288d89683e99fd18fe9f54d4e731a6c474a4f Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Thu, 12 Apr 2012 01:38:35 -0400 Subject: initial check-in --- src/iconv.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 src/iconv.c (limited to 'src/iconv.c') diff --git a/src/iconv.c b/src/iconv.c new file mode 100644 index 0000000..a0938d6 --- /dev/null +++ b/src/iconv.c @@ -0,0 +1,110 @@ +/* + * iconv.c + * Implementation of SUSv4 XCU iconv utility + * Copyright © 2011 Rich Felker + * Licensed under the terms of the GNU General Public License, v2 or later + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + const char *from=0, *to=0; + int b; + iconv_t cd; + char buf[BUFSIZ]; + char outbuf[BUFSIZ*4]; + char *in, *out; + size_t inb; + size_t l; + size_t unitsize=0; + int err=0; + FILE *f; + + while ((b = getopt(argc, argv, "f:t:csl")) != EOF) switch(b) { + case 'l': + puts("UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF32-LE, UCS-2BE, UCS-2LE, WCHAR_T,\n" + "US_ASCII, ISO8859-1, ISO8859-2, ISO8859-3, ISO8859-4, ISO8859-5,\n" + "ISO8859-6, ISO8859-7, ..."); + exit(0); + case 'c': case 's': break; + case 'f': from=optarg; break; + case 't': to=optarg; break; + default: exit(1); + } + + if (!from || !to) { + setlocale(LC_CTYPE, ""); + if (!to) to = nl_langinfo(CODESET); + if (!from) from = nl_langinfo(CODESET); + } + cd = iconv_open(to, from); + if (cd == (iconv_t)-1) { + if (iconv_open(to, "WCHAR_T") == (iconv_t)-1) + fprintf(stderr, "iconv: destination charset %s", to); + else + fprintf(stderr, "iconv: source charset %s", from); + perror(""); + exit(1); + } + if (optind == argc) argv[argc++] = "-"; + + for (; optind < argc; optind++) { + if (argv[optind][0]=='-' && !argv[optind][1]) { + f = stdin; + argv[optind] = "(stdin)"; + } else if (!(f = fopen(argv[optind], "rb"))) { + fprintf(stderr, "iconv: %s", argv[optind]); + perror(""); + err = 1; + continue; + } + inb = 0; + for (;;) { + in = buf; + out = outbuf; + l = fread(buf+inb, 1, sizeof(buf)-inb, f); + inb += l; + if (!inb) break; + if (iconv(cd, &in, &inb, &out, (size_t [1]){sizeof outbuf})==-1 + && errno == EILSEQ) { + if (!unitsize) { + wchar_t wc='0'; + char dummy[4], *dummyp=dummy; + iconv_t cd2 = iconv_open(from, "WCHAR_T"); + if (cd == (iconv_t)-1) { + unitsize = 1; + } else { + iconv(cd2, + (char *[1]){(char *)&wc}, + (size_t[1]){1}, + &dummyp, (size_t[1]){4}); + unitsize = dummyp-dummy; + if (!unitsize) unitsize=1; + } + } + inb-=unitsize; + in+=unitsize; + } + if (inb && !l && errno==EINVAL) break; + if (out>outbuf && !fwrite(outbuf, out-outbuf, 1, stdout)) { + perror("iconv: write error"); + exit(1); + } + if (inb) memmove(buf, in, inb); + } + if (ferror(f)) { + fprintf(stderr, "iconv: %s", argv[optind]); + perror(""); + err = 1; + } + } + return err; +} -- cgit v1.2.1