|
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <iconv.h>
#include <stdlib.h>
/*
* For state-dependent encodings, changes the state of the conversion
* descriptor to initial shift state. Also, outputs the byte sequence
* to change the state to initial state.
* This code is assuming the iconv call for initializing the state
* won't fail due to lack of space in the output buffer.
*/
#define INIT_SHIFT_STATE(cd, fptr, ileft, tptr, oleft) \
{
fptr = NULL; \
ileft = 0; \
tptr = to; \
oleft = BUFSIZ; \
(void) iconv(cd, &fptr, &ileft, &tptr, &oleft); \
(void) fwrite(to, 1, BUFSIZ - oleft, stdout); \
}
int
main(int argc, char **argv)
{
iconv_t cd;
char from[BUFSIZ], to[BUFSIZ];
char *from_code, *to_code;
char *tptr;
const char *fptr;
size_t ileft, oleft, num, ret;
if (argc != 3) {
(void) fprintf(stderr,
"Usage: %s from_codeset to_codeset\\n", argv[0]);
return (1);
}
from_code = argv[1];
to_code = argv[2];
cd = iconv_open((const char *)to_code, (const char *)from_code);
if (cd == (iconv_t)-1) {
/*
* iconv_open failed
*/
(void) fprintf(stderr,
"iconv_open(%s, %s) failed\\n", to_code, from_code);
return (1);
}
ileft = 0;
while ((ileft +=
(num = fread(from + ileft, 1, BUFSIZ - ileft, stdin))) > 0) {
if (num == 0) {
/*
* Input buffer still contains incomplete character
* or sequence. However, no more input character.
*/
/*
* Initializes the conversion descriptor and outputs
* the sequence to change the state to initial state.
*/
INIT_SHIFT_STATE(cd, fptr, ileft, tptr, oleft);
(void) iconv_close(cd);
(void) fprintf(stderr, "Conversion error\\n");
return (1);
}
fptr = from;
for (;;) {
tptr = to;
oleft = BUFSIZ;
ret = iconv(cd, &fptr, &ileft, &tptr, &oleft);
if (ret != (size_t)-1) {
/*
* iconv succeeded
*/
/*
* Outputs converted characters
*/
(void) fwrite(to, 1, BUFSIZ - oleft, stdout);
break;
}
/*
* iconv failed
*/
if (errno == EINVAL) {
/*
* Incomplete character or shift sequence
*/
/*
* Outputs converted characters
*/
(void) fwrite(to, 1, BUFSIZ - oleft, stdout);
/*
* Copies remaining characters in input buffer
* to the top of the input buffer.
*/
(void) memmove(from, fptr, ileft);
/*
* Tries to fill input buffer from stdin
*/
break;
} else if (errno == E2BIG) {
/*
* Lack of space in output buffer
*/
/*
* Outputs converted characters
*/
(void) fwrite(to, 1, BUFSIZ - oleft, stdout);
/*
* Tries to convert remaining characters in
* input buffer with emptied output buffer
*/
continue;
} else if (errno == EILSEQ) {
/*
* Illegal character or shift sequence
*/
/*
* Outputs converted characters
*/
(void) fwrite(to, 1, BUFSIZ - oleft, stdout);
/*
* Initializes the conversion descriptor and
* outputs the sequence to change the state to
* initial state.
*/
INIT_SHIFT_STATE(cd, fptr, ileft, tptr, oleft);
(void) iconv_close(cd);
(void) fprintf(stderr,
"Illegal character or sequence\\n");
return (1);
} else if (errno == EBADF) {
/*
* Invalid conversion descriptor.
* Actually, this shouldn't happen here.
*/
(void) fprintf(stderr, "Conversion error\\n");
return (1);
} else {
/*
* This errno is not defined
*/
(void) fprintf(stderr, "iconv error\\n");
return (1);
}
}
}
/*
* Initializes the conversion descriptor and outputs
* the sequence to change the state to initial state.
*/
INIT_SHIFT_STATE(cd, fptr, ileft, tptr, oleft);
(void) iconv_close(cd);
return (0);
}
|