iconv.c 2.5 KB

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