aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2014-04-13 15:49:15 -0500
committerRob Landley <rob@landley.net>2014-04-13 15:49:15 -0500
commit603e206e53bf5709e596884aec8933bda0b848b6 (patch)
tree71ffa107b906ae7ef2ef9142d1da752ecfb6811d
parent85224dd4982ba22f448e8cc1319bb3252b2a6671 (diff)
downloadtoybox-603e206e53bf5709e596884aec8933bda0b848b6.tar.gz
iconv cleanup.
-rw-r--r--toys/pending/iconv.c63
1 files changed, 33 insertions, 30 deletions
diff --git a/toys/pending/iconv.c b/toys/pending/iconv.c
index d9f28176..847fcfd1 100644
--- a/toys/pending/iconv.c
+++ b/toys/pending/iconv.c
@@ -2,13 +2,13 @@
*
* Copyright 2014 Felix Janda <felix.janda@posteo.de>
*
- * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/iconv.html
USE_ICONV(NEWTOY(iconv, "t:f:", TOYFLAG_USR|TOYFLAG_BIN))
config ICONV
bool "iconv"
- default n
+ default y
help
usage: iconv [-f FROM] [-t TO] [FILE...]
@@ -16,7 +16,6 @@ config ICONV
-f convert from (default utf8)
-t convert to (default utf8)
-
*/
#define FOR_iconv
@@ -26,42 +25,46 @@ config ICONV
GLOBALS(
char *from;
char *to;
-)
-iconv_t ic; // Can't be put into GLOBALS because iconv_t is defined in iconv.h
+ void *ic;
+)
static void do_iconv(int fd, char *name)
{
- size_t inleft = 0, outleft = 2048;
- char *in = toybuf, *out = toybuf + 2048;
+ char *outstart = toybuf+2048;
+ size_t inleft = 0;
+ int len = 1;
- while (1) {
- if (!inleft || (errno == EINVAL)) {
- memmove(in, toybuf, inleft);
- if (!(inleft += read(fd, toybuf + inleft, 2048 - inleft))) {
- xwrite(1, toybuf + 2048, 2048 - outleft);
- break;
+ do {
+ size_t outleft = 2048;
+ char *in = toybuf, *out = outstart;
+
+ len = read(fd, toybuf+inleft, 2048-inleft);
+
+ if (len < 0) perror_msg("read '%s'");
+ inleft += len;
+
+ do {
+ if (iconv(TT.ic, &in, &inleft, &out, &outleft) == -1
+ && (errno == EILSEQ || (in == toybuf && errno == EINVAL)))
+ {
+ if (outleft) {
+ // Skip first byte of illegal sequence to avoid endless loops
+ *(out++) = *(in++);
+ inleft--;
+ }
}
- in = toybuf;
- } else if (errno == E2BIG) {
- xwrite(1, toybuf + 2048, 2048 - outleft);
- out = toybuf + 2048;
- outleft = 2048;
- } else if (errno == EILSEQ) {
- in++;
- inleft--;
- }
- if (iconv(ic, &in, &inleft, &out, &outleft) != (size_t)-1) errno = 0;
- }
+ xwrite(1, outstart, out-outstart);
+ // Top off input buffer
+ memmove(in, toybuf, inleft);
+ } while (len < 1 && inleft);
+ } while (len > 0);
}
void iconv_main(void)
{
- char *from = "utf8", *to = "utf8";
-
- if (toys.optflags & FLAG_f) from = TT.from;
- if (toys.optflags & FLAG_t) to = TT.to;
- if ((ic = iconv_open(to, from)) == (iconv_t)-1) error_exit("iconv_open");
+ TT.ic = iconv_open(TT.to ? TT.to : "utf8", TT.from ? TT.from : "utf8");
+ if (TT.ic == (iconv_t)-1) error_exit("bad encoding");
loopfiles(toys.optargs, do_iconv);
- if (CFG_TOYBOX_FREE) iconv_close(ic);
+ if (CFG_TOYBOX_FREE) iconv_close(TT.ic);
}