iconv.c (2577B)
1 /* 2 * iconv.c 3 * Implementation of SUSv4 XCU iconv utility 4 * Copyright © 2011 Rich Felker 5 * Licensed under the terms of the GNU General Public License, v2 or later 6 */ 7 8 #include <stdlib.h> 9 #include <stdio.h> 10 #include <iconv.h> 11 #include <locale.h> 12 #include <langinfo.h> 13 #include <unistd.h> 14 #include <errno.h> 15 #include <string.h> 16 17 int main(int argc, char **argv) 18 { 19 const char *from=0, *to=0; 20 int b; 21 iconv_t cd; 22 char buf[BUFSIZ]; 23 char outbuf[BUFSIZ*4]; 24 char *in, *out; 25 size_t inb; 26 size_t l; 27 size_t unitsize=0; 28 int err=0; 29 FILE *f; 30 31 while ((b = getopt(argc, argv, "f:t:csl")) != EOF) switch(b) { 32 case 'l': 33 puts("UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF32-LE, UCS-2BE, UCS-2LE, WCHAR_T,\n" 34 "US_ASCII, ISO8859-1, ISO8859-2, ISO8859-3, ISO8859-4, ISO8859-5,\n" 35 "ISO8859-6, ISO8859-7, ..."); 36 exit(0); 37 case 'c': case 's': break; 38 case 'f': from=optarg; break; 39 case 't': to=optarg; break; 40 default: exit(1); 41 } 42 43 if (!from || !to) { 44 setlocale(LC_CTYPE, ""); 45 if (!to) to = nl_langinfo(CODESET); 46 if (!from) from = nl_langinfo(CODESET); 47 } 48 cd = iconv_open(to, from); 49 if (cd == (iconv_t)-1) { 50 if (iconv_open(to, "WCHAR_T") == (iconv_t)-1) 51 fprintf(stderr, "iconv: destination charset %s: ", to); 52 else 53 fprintf(stderr, "iconv: source charset %s: ", from); 54 perror(""); 55 exit(1); 56 } 57 if (optind == argc) argv[argc++] = "-"; 58 59 for (; optind < argc; optind++) { 60 if (argv[optind][0]=='-' && !argv[optind][1]) { 61 f = stdin; 62 argv[optind] = "(stdin)"; 63 } else if (!(f = fopen(argv[optind], "rb"))) { 64 fprintf(stderr, "iconv: %s: ", argv[optind]); 65 perror(""); 66 err = 1; 67 continue; 68 } 69 inb = 0; 70 for (;;) { 71 in = buf; 72 out = outbuf; 73 l = fread(buf+inb, 1, sizeof(buf)-inb, f); 74 inb += l; 75 if (!inb) break; 76 if (iconv(cd, &in, &inb, &out, (size_t [1]){sizeof outbuf})==-1 77 && errno == EILSEQ) { 78 if (!unitsize) { 79 wchar_t wc='0'; 80 char dummy[4], *dummyp=dummy; 81 iconv_t cd2 = iconv_open(from, "WCHAR_T"); 82 if (cd == (iconv_t)-1) { 83 unitsize = 1; 84 } else { 85 iconv(cd2, 86 (char *[1]){(char *)&wc}, 87 (size_t[1]){1}, 88 &dummyp, (size_t[1]){4}); 89 unitsize = dummyp-dummy; 90 if (!unitsize) unitsize=1; 91 } 92 } 93 inb-=unitsize; 94 in+=unitsize; 95 } 96 if (inb && !l && errno==EINVAL) break; 97 if (out>outbuf && !fwrite(outbuf, out-outbuf, 1, stdout)) { 98 perror("iconv: write error"); 99 exit(1); 100 } 101 if (inb) memmove(buf, in, inb); 102 } 103 if (ferror(f)) { 104 fprintf(stderr, "iconv: %s: ", argv[optind]); 105 perror(""); 106 err = 1; 107 } 108 } 109 return err; 110 }