2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
13 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
39 int cflag
; /* skip invalid characters */
40 int sflag
; /* silent */
41 int lflag
; /* list conversions */
43 void iconv_file(FILE *, const char *);
44 extern int list_codesets(void);
46 iconv_t ich
; /* iconv(3c) lib handle */
47 size_t (*pconv
)(const char **iptr
, size_t *ileft
,
48 char **optr
, size_t *oleft
);
51 lib_iconv(const char **iptr
, size_t *ileft
, char **optr
, size_t *oleft
)
53 return (iconv(ich
, iptr
, ileft
, optr
, oleft
));
59 (void) fprintf(stderr
, gettext(
60 "usage: %s [-cs] [-f from-codeset] [-t to-codeset] "
61 "[file ...]\n"), progname
);
62 (void) fprintf(stderr
, gettext("\t%s -l\n"), progname
);
67 main(int argc
, char **argv
)
70 char *fslash
, *tslash
;
74 progname
= getprogname();
76 (void) setlocale(LC_ALL
, "");
78 #if !defined(TEXT_DOMAIN)
79 #define TEXT_DOMAIN "SYS_TEST"
81 (void) textdomain(TEXT_DOMAIN
);
83 while ((c
= getopt(argc
, argv
, "cdlsf:t:")) != EOF
) {
109 if (from_cs
!= NULL
|| to_cs
!= NULL
|| optind
!= argc
)
111 exit(list_codesets());
115 from_cs
= nl_langinfo(CODESET
);
117 to_cs
= nl_langinfo(CODESET
);
120 * If either "from" or "to" contains a slash,
121 * then we're using charmaps.
123 fslash
= strchr(from_cs
, '/');
124 tslash
= strchr(to_cs
, '/');
125 if (fslash
!= NULL
|| tslash
!= NULL
) {
126 charmap_init(to_cs
, from_cs
);
131 ich
= iconv_open(to_cs
, from_cs
);
132 if (ich
== ((iconv_t
)-1)) {
135 (void) fprintf(stderr
,
136 _("Not supported %s to %s\n"),
140 (void) fprintf(stderr
,
141 _("iconv_open failed: %s\n"),
150 if (optind
== argc
||
151 (optind
== argc
- 1 && 0 == strcmp(argv
[optind
], "-"))) {
152 iconv_file(stdin
, "stdin");
153 exit(warnings
? 1 : 0);
156 for (; optind
< argc
; optind
++) {
157 fp
= fopen(argv
[optind
], "r");
159 perror(argv
[optind
]);
162 iconv_file(fp
, argv
[optind
]);
165 exit(warnings
? 1 : 0);
169 * Conversion buffer sizes:
171 * The input buffer has room to prepend one mbs character if needed for
172 * handling a left-over at the end of a previous conversion buffer.
174 * Conversions may grow or shrink data, so using a larger output buffer
175 * to reduce the likelihood of leftover input buffer data in each pass.
177 #define IBUFSIZ (MB_LEN_MAX + BUFSIZ)
178 #define OBUFSIZ (2 * BUFSIZ)
181 iconv_file(FILE *fp
, const char *fname
)
183 static char ibuf
[IBUFSIZ
];
184 static char obuf
[OBUFSIZ
];
188 size_t ileft
, oleft
, ocnt
;
194 iptr
= ibuf
+ MB_LEN_MAX
;
196 while ((nr
= fread(ibuf
+MB_LEN_MAX
, 1, BUFSIZ
, fp
)) > 0) {
198 assert(iptr
<= ibuf
+MB_LEN_MAX
);
199 assert(ileft
<= MB_LEN_MAX
);
207 * Note: the *pconv function is either iconv(3c) or our
208 * private equivalent when using charmaps. Both update
209 * ileft, oleft etc. even when conversion stops due to
210 * an illegal sequence or whatever, so we need to copy
211 * the partially converted buffer even on error.
214 rc
= (*pconv
)(&iptr
, &ileft
, &optr
, &oleft
);
217 ocnt
= OBUFSIZ
- oleft
;
219 nw
= fwrite(obuf
, 1, ocnt
, stdout
);
228 if (rc
== (size_t)-1) {
229 switch (iconv_errno
) {
231 case E2BIG
: /* no room in output buffer */
234 case EINVAL
: /* incomplete sequence on input */
236 (void) fprintf(stderr
,
237 _("Incomplete sequence in %s at offset %lld\n"),
238 fname
, offset
- ileft
);
241 * Copy the remainder to the space reserved
242 * at the start of the input buffer.
245 if (ileft
<= MB_LEN_MAX
) {
246 char *p
= ibuf
+MB_LEN_MAX
-ileft
;
247 (void) memmove(p
, iptr
, ileft
);
249 continue; /* read again */
252 * Should not see ileft > MB_LEN_MAX,
253 * but if we do, handle as EILSEQ.
257 case EILSEQ
: /* invalid sequence on input */
259 (void) fprintf(stderr
,
260 _("Illegal sequence in %s at offset %lld\n"),
261 fname
, offset
- ileft
);
262 (void) fprintf(stderr
,
263 _("bad seq: \\x%02x\\x%02x\\x%02x\n"),
280 (void) fprintf(stderr
,
281 _("iconv error (%s) in file $s at offset %lld\n"),
282 strerror(iconv_errno
), fname
,
288 /* normal iconv return */
290 iptr
= ibuf
+ MB_LEN_MAX
;
295 * Flush any shift encodings.
301 (*pconv
)(&iptr
, &ileft
, &optr
, &oleft
);
302 ocnt
= OBUFSIZ
- oleft
;
304 nw
= fwrite(obuf
, 1, ocnt
, stdout
);