1 /* $NetBSD: iconv.c,v 1.4 2003/10/20 12:56:18 yamt Exp $ */ 2 /* $DragonFly: src/usr.bin/iconv/iconv.c,v 1.2 2008/07/10 18:29:51 swildner Exp $ */ 3 4 /*- 5 * Copyright (c)2003 Citrus Project, 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/endian.h> 31 #include <err.h> 32 #include <errno.h> 33 #include <iconv.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 39 static void 40 usage(void) 41 { 42 fprintf(stderr, 43 "usage:\n" 44 "\t%s [-cs] -f <from> -t <to> [file ...]\n" 45 "\t%s -l\n", 46 getprogname(), getprogname()); 47 exit(1); 48 } 49 50 /* 51 * qsort() helper function 52 */ 53 static int 54 scmp(const void *v1, const void *v2) 55 { 56 const char * const *s1 = v1; 57 const char * const *s2 = v2; 58 59 return(strcasecmp(*s1, *s2)); 60 } 61 62 static void 63 show_codesets(void) 64 { 65 char **list; 66 size_t sz, i; 67 68 if (__iconv_get_list(&list, &sz)) 69 err(EXIT_FAILURE, "__iconv_get_list()"); 70 71 qsort(list, sz, sizeof(char *), scmp); 72 73 for (i=0; i<sz; i++) { 74 printf("%s\n", list[i]); 75 } 76 77 __iconv_free_list(list, sz); 78 } 79 80 #define INBUFSIZE 1024 81 #define OUTBUFSIZE (INBUFSIZE*2) 82 83 static void 84 do_conv(FILE *fp, const char *from, const char *to, int silent, 85 int hide_invalid) 86 { 87 char inbuf[INBUFSIZE], outbuf[OUTBUFSIZE], *out; 88 const char *in; 89 size_t inbytes, outbytes, invalids; 90 ssize_t ret; 91 iconv_t cd; 92 u_int32_t flags = 0; 93 94 if (hide_invalid) 95 flags |= __ICONV_F_HIDE_INVALID; 96 cd = iconv_open(to, from); 97 if (cd == (iconv_t)-1) 98 err(EXIT_FAILURE, "iconv_open(%s, %s)", to, from); 99 100 invalids = 0; 101 while ((inbytes = fread(inbuf, 1, INBUFSIZE, fp)) > 0) { 102 in = inbuf; 103 while (inbytes>0) { 104 size_t inval; 105 106 out = outbuf; 107 outbytes = OUTBUFSIZE; 108 ret = __iconv(cd, &in, &inbytes, &out, &outbytes, 109 flags, &inval); 110 invalids += inval; 111 if (ret == -1 && errno != E2BIG) { 112 /* 113 * XXX: iconv(3) is bad interface. 114 * invalid character count is lost here. 115 * instead, we just provide __iconv function. 116 */ 117 if (errno != EINVAL || in == inbuf) 118 err(EXIT_FAILURE, "iconv()"); 119 120 /* incomplete input character */ 121 memmove(inbuf, in, inbytes); 122 ret = fread(inbuf+inbytes, 1, 123 INBUFSIZE-inbytes, fp); 124 if (ret == 0) { 125 if (feof(fp)) 126 errx(EXIT_FAILURE, 127 "iconv(): %s", 128 strerror(EINVAL)); 129 else 130 err(EXIT_FAILURE, "fread()"); 131 } 132 in = inbuf; 133 inbytes += ret; 134 } 135 if (outbytes < OUTBUFSIZE) 136 fwrite(outbuf, 1, OUTBUFSIZE-outbytes, stdout); 137 } 138 } 139 /* reset the shift state of the output buffer */ 140 outbytes = OUTBUFSIZE; 141 out = outbuf; 142 ret = iconv(cd, NULL, NULL, &out, &outbytes); 143 if (ret == -1) 144 err(EXIT_FAILURE, "iconv()"); 145 if (outbytes < OUTBUFSIZE) 146 fwrite(outbuf, 1, OUTBUFSIZE-outbytes, stdout); 147 148 if (invalids > 0 && !silent) 149 warnx("warning: invalid characters: %lu", 150 (unsigned long)invalids); 151 152 iconv_close(cd); 153 } 154 155 int 156 main(int argc, char **argv) 157 { 158 int ch, i; 159 int opt_l = 0, opt_s = 0, opt_c = 0; 160 char *opt_f = NULL, *opt_t = NULL; 161 FILE *fp; 162 163 while ((ch=getopt(argc, argv, "cslf:t:")) != -1) { 164 switch (ch) { 165 case 'c': 166 opt_c = 1; 167 break; 168 case 's': 169 opt_s = 1; 170 break; 171 case 'l': 172 /* list */ 173 opt_l = 1; 174 break; 175 case 'f': 176 /* from */ 177 opt_f = strdup(optarg); 178 break; 179 case 't': 180 /* to */ 181 opt_t = strdup(optarg); 182 break; 183 default: 184 usage(); 185 } 186 } 187 argc-=optind; 188 argv+=optind; 189 if (opt_l) { 190 if (argc>0 || opt_s || opt_f != NULL || opt_t != NULL) { 191 warnx("%s: -l should be specified solely.", 192 getprogname()); 193 usage(); 194 } 195 show_codesets(); 196 } else { 197 if (opt_f == NULL || opt_t == NULL) 198 usage(); 199 200 if (argc == 0) 201 do_conv(stdin, opt_f, opt_t, opt_s, opt_c); 202 else { 203 for (i=0; i<argc; i++) { 204 fp = fopen(argv[i], "r"); 205 if (fp == NULL) 206 errx(EXIT_FAILURE, "%s: %s:%s", 207 getprogname(), argv[i], 208 strerror(errno)); 209 do_conv(fp, opt_f, opt_t, opt_s, opt_c); 210 fclose(fp); 211 } 212 } 213 } 214 215 return(EXIT_SUCCESS); 216 } 217