Blame bin/iconv.c

3a5018
/*
3a5018
 * iconv.c
3a5018
 * Implementation of SUSv4 XCU iconv utility
3a5018
 * Copyright © 2011 Rich Felker
3a5018
 * Licensed under the terms of the GNU General Public License, v2 or later
3a5018
 */
3a5018
3a5018
#include <stdlib.h>
3a5018
#include <stdio.h>
3a5018
#include <iconv.h>
3a5018
#include <locale.h>
3a5018
#include <langinfo.h>
3a5018
#include <unistd.h>
3a5018
#include <errno.h>
3a5018
#include <string.h>
3a5018
3a5018
int main(int argc, char **argv)
3a5018
{
3a5018
	const char *from=0, *to=0;
3a5018
	int b;
3a5018
	iconv_t cd;
3a5018
	char buf[BUFSIZ];
3a5018
	char outbuf[BUFSIZ*4];
3a5018
	char *in, *out;
3a5018
	size_t inb;
3a5018
	size_t l;
3a5018
	size_t unitsize=0;
3a5018
	int err=0;
3a5018
	FILE *f;
3a5018
3a5018
	while ((b = getopt(argc, argv, "f:t:csl")) != EOF) switch(b) {
3a5018
	case 'l':
3a5018
		puts("UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF32-LE, UCS-2BE, UCS-2LE, WCHAR_T,\n"
3a5018
			"US_ASCII, ISO8859-1, ISO8859-2, ISO8859-3, ISO8859-4, ISO8859-5,\n"
3a5018
			"ISO8859-6, ISO8859-7, ...");
3a5018
		exit(0);
3a5018
	case 'c': case 's': break;
3a5018
	case 'f': from=optarg; break;
3a5018
	case 't': to=optarg; break;
3a5018
	default: exit(1);
3a5018
	}
3a5018
3a5018
	if (!from || !to) {
3a5018
		setlocale(LC_CTYPE, "");
3a5018
		if (!to) to = nl_langinfo(CODESET);
3a5018
		if (!from) from = nl_langinfo(CODESET);
3a5018
	}
3a5018
	cd = iconv_open(to, from);
3a5018
	if (cd == (iconv_t)-1) {
3a5018
		if (iconv_open(to, "WCHAR_T") == (iconv_t)-1)
3a5018
			fprintf(stderr, "iconv: destination charset %s: ", to);
3a5018
		else
3a5018
			fprintf(stderr, "iconv: source charset %s: ", from);
3a5018
		perror("");
3a5018
		exit(1);
3a5018
	}
3a5018
	if (optind == argc) argv[argc++] = "-";
3a5018
3a5018
	for (; optind < argc; optind++) {
3a5018
		if (argv[optind][0]=='-' && !argv[optind][1]) {
3a5018
			f = stdin;
3a5018
			argv[optind] = "(stdin)";
3a5018
		} else if (!(f = fopen(argv[optind], "rb"))) {
3a5018
			fprintf(stderr, "iconv: %s: ", argv[optind]);
3a5018
			perror("");
3a5018
			err = 1;
3a5018
			continue;
3a5018
		}
3a5018
		inb = 0;
3a5018
		for (;;) {
3a5018
			in = buf;
3a5018
			out = outbuf;
3a5018
			l = fread(buf+inb, 1, sizeof(buf)-inb, f);
3a5018
			inb += l;
3a5018
			if (!inb) break;
3a5018
			if (iconv(cd, &in, &inb, &out, (size_t [1]){sizeof outbuf})==-1
3a5018
			 && errno == EILSEQ) {
3a5018
				if (!unitsize) {
3a5018
					wchar_t wc='0';
3a5018
					char dummy[4], *dummyp=dummy;
3a5018
					iconv_t cd2 = iconv_open(from, "WCHAR_T");
3a5018
					if (cd == (iconv_t)-1) {
3a5018
						unitsize = 1;
3a5018
					} else {
3a5018
						iconv(cd2,
3a5018
							(char *[1]){(char *)&wc},
3a5018
							(size_t[1]){1},
3a5018
							&dummyp, (size_t[1]){4});
3a5018
						unitsize = dummyp-dummy;
3a5018
						if (!unitsize) unitsize=1;
3a5018
					}
3a5018
				}
3a5018
				inb-=unitsize;
3a5018
				in+=unitsize;
3a5018
			}
3a5018
			if (inb && !l && errno==EINVAL) break;
3a5018
			if (out>outbuf && !fwrite(outbuf, out-outbuf, 1, stdout)) {
3a5018
				perror("iconv: write error");
3a5018
				exit(1);
3a5018
			}
3a5018
			if (inb) memmove(buf, in, inb);
3a5018
		}
3a5018
		if (ferror(f)) {
3a5018
			fprintf(stderr, "iconv: %s: ", argv[optind]);
3a5018
			perror("");
3a5018
			err = 1;
3a5018
		}
3a5018
	}
3a5018
	return err;
3a5018
}