#include <stdio.h>
#include <libgen.h>
#include <stdlib.h>
#include <unistd.h>
#include <locale.h>
#include <iconv.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/wait.h>
char * ME;
int status;
int flag_display = 1;
int flag_bubun = 1;
void
usage(int status)
{
fprintf(stderr, "Usage: %s [-b] [-d] to-code\n", ME);
exit(status);
}
void
chkprint(char *format, ...)
{
va_list ap;
va_start(ap, format);
if (0 != flag_display) {
(void) vfprintf(stdout, format, ap);
}
va_end(ap);
}
void
validate(uint_t i, iconv_t cd, iconv_t cd2, iconv_t cd3)
{
char source_buf[1024];
char result_buf[1024];
char tmp_buf[1024];
char * source;
char * result;
char * tmp;
size_t source_len;
size_t result_len;
size_t result_len2;
size_t tmp_len;
size_t s;
int j;
ushort_t *shortp;
uint_t *intp;
#define PREPARE_ILLEGALUTF8 \
if (i == 0xfffe) { \
source_buf[0] = 0xef; \
source_buf[1] = 0xbf; \
source_buf[2] = 0xbe; \
source_buf[3] = 0x00; \
source = source_buf; \
source_len = 3; \
chkprint("U+%04x\t** %x **", i, 0xefbfbe); \
} else if (i == 0xffff) { \
source_buf[0] = 0xef; \
source_buf[1] = 0xbf; \
source_buf[2] = 0xbf; \
source_buf[3] = 0x00; \
source = source_buf; \
source_len = 3; \
chkprint("U+%04x\t** %x **", i, 0xefbfbf); \
} else if (i > 0x7fffffff) { \
source_buf[0] = 0x0; \
source_buf[1] = 0x0; \
source_buf[2] = 0x0; \
source_buf[3] = 0x0; \
source_buf[4] = 0x0; \
source_buf[5] = 0xfe; \
source_buf[6] = 0x0; \
source = source_buf; \
source_len = 7; \
chkprint("U+%04x\t** %x **", i, 0xfe); \
}
#define DATASIZE 4
\
\
\
#define PREPAREUTF8 \
tmp = tmp_buf; \
tmp_len = DATASIZE; \
intp = (uint_t*)&tmp_buf[0]; \
*intp = i; \
source = source_buf; \
source_len = sizeof (source_buf); \
\
chkprint("U+%04x", i); \
s = iconv(cd2, (const char**)&tmp, &tmp_len, &source, &source_len); \
if (s != 0) { \
chkprint(" \n stopped \n"); \
fprintf(stderr, "fail to convert Unicode to UTF-8\n"); \
exit (status); \
} \
chkprint("\t0x"); \
for( j = 0; j < sizeof (source_buf) - source_len; j++) \
chkprint("%02x", (uchar_t)source_buf[j]); \
source_len = sizeof (source_buf) - source_len; \
source = &source_buf[0];
#define COMPARE_ERROR \
chkprint("\t-> 0x");\
for (j = 0; j < sizeof (tmp_buf) - tmp_len; j++) { \
chkprint("%02x", (uchar_t)tmp_buf[j]);\
} \
chkprint("\n warning \n"); \
fprintf(stderr, " Converting answer is not the same for (U+%04x)\n", \
i);
#define COMPARE \
tmp = tmp_buf; \
tmp_len = sizeof (tmp_buf); \
result = result_buf; \
result_len2 = sizeof (result_buf) - result_len; \
s = iconv(cd3, (const char**)&result, &result_len2, &tmp, &tmp_len); \
if (s != 0) { \
chkprint(" \n WARNING \n"); \
fprintf(stderr, "fail to convert Orignal Codeset to UTF-8\n",\
i); \
fprintf(stderr, "errno=%d %d %d\n", \
errno, \
sizeof (result_buf) - result_len - result_len2, \
result - result_buf); \
exit (status); \
} \
chkprint("\t"); \
if (sizeof (tmp_buf) - tmp_len != source_len) { \
COMPARE_ERROR \
} else { \
for (j = 0; j < source_len; j++) { \
if ((uchar_t)tmp_buf[j] != (uchar_t)source_buf[j]) { \
COMPARE_ERROR \
} \
}\
}
if (i == 0xfffe || i == 0xffff || i > 0x7fffffff) {
PREPARE_ILLEGALUTF8
} else {
PREPAREUTF8
}
result = result_buf;
result_len = sizeof (result_buf);
tmp_len = source_len;
s = iconv(cd, (const char**)&source, &source_len, &result,
&result_len);
status = 1;
if (i == 0xfffe || i == 0xffff || i > 0x7fffffff) {
if ((((size_t)0) == s) ||
(errno != EILSEQ)) {
fprintf(stderr, "EILSEQ expected for 0x%x: %d %d %d\n",
i,
errno,
source_len,
source - source_buf);
}
}
if (((size_t)(0)) == s) {
if ((source_len != 0) ||
((source - source_buf) != tmp_len) ||
((result - result_buf + result_len) !=
sizeof (result_buf))) {
fprintf(stderr, ": %d %d %d\n",
errno,
source_len,
source - source_buf);
exit(status);
}
chkprint("\t0x");
for( j = 0; j < sizeof (result_buf) - result_len ; j++)
chkprint("%02x", (uchar_t)result_buf[j]);
source_len = tmp_len;
COMPARE
chkprint("\n");
return;
}
status += 1;
if (((size_t)(-1)) == s) {
if (errno == EILSEQ) {
if (((source - source_buf) !=
(tmp_len - source_len)) ||
((result - result_buf + result_len) !=
sizeof (result_buf))) {
fprintf(stderr, ": %d %d %d\n",
errno,
source_len,
source - source_buf);
exit(status);
}
chkprint("\tEILSEQ\n", i);
return;
}
fprintf(stderr, "Error for source U+%04x: %d %d %d %d %d\n",
i,
errno,
(DATASIZE) - source_len,
source - source_buf,
(sizeof (result_buf)) - result_len,
result - result_buf);
exit(status);
}
status += 1;
exit(status);
}
main(int argc, char ** argv)
{
int r;
char * p;
iconv_t cd;
iconv_t cd2;
iconv_t cd3;
uint_t i, j, k;
ME = basename(argv[0]);
setlocale(LC_ALL, "");
status = 100;
for (j = 1; j < argc; j++) {
if (argv[j][0] != '-')
break;
for (k = 1; ; k++) {
if (argv[j][k] == '\0')
break;
if (argv[j][k] == 'b') {
flag_bubun = 0;
continue;
}
if (argv[j][k] == 'd') {
flag_display = 0;
continue;
}
}
}
if (j >= argc) usage(-1);
chkprint( "#UCS-4\tUTF-8\t* %s *\n", argv[j]);
cd = iconv_open( argv[j], "UTF-8");
if (((iconv_t)(-1)) == cd) {
perror("iconv_open");
exit(status);
}
cd2 = iconv_open("UTF-8", "UCS-4");
if (((iconv_t)(-1)) == cd2) {
perror("iconv_open for UTF-8");
exit(status);
}
cd3 = iconv_open("UTF-8", argv[j]);
if (((iconv_t)(-1)) == cd3) {
perror("iconv_open for reverse");
exit(status);
}
if (flag_bubun) {
for (i = 0; i <= 0xff; i++)
validate(i, cd, cd2, cd3);
validate(0x100, cd, cd2, cd3);
validate(0x3ff, cd, cd2, cd3);
validate(0x400, cd, cd2, cd3);
validate(0xfff, cd, cd2, cd3);
validate(0x1000, cd, cd2, cd3);
validate(0x3fff, cd, cd2, cd3);
validate(0x4000, cd, cd2, cd3);
validate(0xfffd, cd, cd2, cd3);
validate(0xfffe, cd, cd2, cd3);
validate(0xffff, cd, cd2, cd3);
validate(0x10000, cd, cd2, cd3);
validate(0x3ffff, cd, cd2, cd3);
validate(0x40000, cd, cd2, cd3);
validate(0xfffff, cd, cd2, cd3);
validate(0x100000, cd, cd2, cd3);
validate(0x1fffff, cd, cd2, cd3);
validate(0x200000, cd, cd2, cd3);
validate(0x3fffff, cd, cd2, cd3);
validate(0x400000, cd, cd2, cd3);
validate(0xffffff, cd, cd2, cd3);
validate(0x1000000, cd, cd2, cd3);
validate(0x3ffffff, cd, cd2, cd3);
validate(0x4000000, cd, cd2, cd3);
validate(0xfffffff, cd, cd2, cd3);
validate(0x10000000, cd, cd2, cd3);
validate(0x7fffffff, cd, cd2, cd3);
validate(0x80000000, cd, cd2, cd3);
} else {
int k;
for (i = 0, k = 0; i <= 0x80000000; i++, k++) {
validate(i, cd, cd2, cd3);
if ((k == 0x1000000) &&
(0 == flag_display)) {
printf(" i < 0x%x: checked\n", i);
k = 0;
}
}
}
status = 200;
r = iconv_close(cd);
if (-1 == r) {
perror("iconv_close");
exit(status);
}
r = iconv_close(cd2);
if (-1 == r) {
perror("iconv_close for UTF-8");
exit(status);
}
r = iconv_close(cd3);
if (-1 == r) {
perror("iconv_close for reverse");
exit(status);
}
return (0);
}