From: Michael Orlitzky Date: Sun, 5 Jul 2026 18:00:46 +0000 (-0400) Subject: main.c: begin adding suffix tests, refactor... X-Git-Url: https://gitweb.michael.orlitzky.com/?a=commitdiff_plain;h=633e5fc1703b1465eab781a8c852e8105362b708;p=iconv-quirks.git main.c: begin adding suffix tests, refactor... --- diff --git a/main.c b/main.c index c19c7e0..dc47500 100644 --- a/main.c +++ b/main.c @@ -1,7 +1,6 @@ #include #include #include -#include #include /* The various invalid sequences can be inferred from the table of @@ -34,6 +33,7 @@ #define SUCCESS 0 #define FAILURE 1 +#define UNSUPPORTED 2 /* also success if the standard allows it */ /* Open a conversion descriptor by reference. Wraps the boilerplate * error reporting when iconv_open() fails. @@ -92,32 +92,6 @@ int _my_iconv_close(iconv_t* cd) { return SUCCESS; } -/* - * Open and close a conversion descriptor (basic sanity test). - */ -int test_open_close() { - iconv_t cd; - const char* tocode = "ASCII"; - const char* fromcode = "ASCII"; - - printf("can iconv_open() and iconv_close() a conversion descriptor..."); - if (_my_iconv_open(&cd, tocode, fromcode) == FAILURE) { - printf("FAIL\n"); - return FAILURE; - } - - if (_my_iconv_close(&cd) == SUCCESS) { - printf("OK\n"); - } - else { - printf("FAIL\n"); - return FAILURE; - } - - return SUCCESS; -} - - /* * Ensure that iconv_open() supports the given indicator suffix. */ @@ -132,7 +106,7 @@ int test_iconv_open_supports_suffix(const char* suffix) { switch (errno) { case EINVAL: printf("OK (EINVAL, not supported)\n"); - return SUCCESS; + return UNSUPPORTED; default: printf("FAIL (errno=%d, unexpected error)\n", errno); return FAILURE; @@ -232,12 +206,13 @@ int test_iconv_invalid_char_is_eilseq() { } size_t insize = 1, outsize = 1; - char* inbuf = (char*)malloc(insize); - char* outbuf = (char*)malloc(outsize); + char inbuf[1], outbuf[1]; + char* inptr = inbuf; + char* outptr = outbuf; inbuf[0] = ASCII_MAX + 1; // not ascii - size_t result = iconv(cd, &inbuf, &insize, &outbuf, &outsize); + size_t result = iconv(cd, &inptr, &insize, &outptr, &outsize); if (result == (size_t)(-1)) { int saved_errno = errno; // iconv_close() clobbers it @@ -280,14 +255,15 @@ int test_iconv_incomplete_multibyte_is_einval() { } size_t insize = 1, outsize = 1; - char* inbuf = (char*)malloc(insize); - char* outbuf = (char*)malloc(outsize); + char inbuf[1], outbuf[1]; + char* inptr = inbuf; + char* outptr = outbuf; // a single byte in the input buffer that demands // a (nonexistent) subsequent byte inbuf[0] = MULTIBYTE_MIN; - size_t result = iconv(cd, &inbuf, &insize, &outbuf, &outsize); + size_t result = iconv(cd, &inptr, &insize, &outptr, &outsize); if (result == (size_t)(-1)) { int saved_errno = errno; // iconv_close() clobbers it @@ -322,15 +298,16 @@ int test_iconv_too_big_is_e2big() { } size_t insize = 2, outsize = 1; - char* inbuf = (char*)malloc(insize); - char* outbuf = (char*)malloc(outsize); + char inbuf[2], outbuf[1]; + char* inptr = inbuf; + char* outptr = outbuf; // a single byte in the input buffer that demands // a (nonexistent) subsequent byte inbuf[0] = 'h'; inbuf[1] = 'i'; - size_t result = iconv(cd, &inbuf, &insize, &outbuf, &outsize); + size_t result = iconv(cd, &inptr, &insize, &outptr, &outsize); if (result == (size_t)(-1)) { int saved_errno = errno; // iconv_close() clobbers it @@ -345,7 +322,7 @@ int test_iconv_too_big_is_e2big() { return SUCCESS; } else { - printf("FAIL (errno=%d, unexpected)\n", saved_errno); + printf("FAIL (errno=%d)\n", saved_errno); return FAILURE; } } @@ -354,16 +331,77 @@ int test_iconv_too_big_is_e2big() { return FAILURE; } + +/* If a sequence of input bytes does not form a valid character or + * shift sequence in the input codeset: If the //IGNORE indicator + * suffix was specified when the conversion descriptor cd was opened + * and the byte sequence is immediately followed by a valid character + * or shift sequence, the sequence of bytes shall be discarded and + * conversion shall continue from the immediately following valid + * character or shift sequence. + * + * This shall not be treated as an error. + * -------------------------------------- + */ +int test_iconv_ignore_ignores_invalid() { + iconv_t cd; + const char* fromcode = "ASCII"; + const char* tocode = "ASCII//IGNORE"; + + printf("iconv() ignores invalid input with no errors..."); + if (_my_iconv_open(&cd, tocode, fromcode) == FAILURE) { + printf("ERROR (iconv_open)\n"); + return FAILURE; + } + + size_t insize = 4, outsize = 3; + char inbuf[4], outbuf[3] = {0}; + char* inptr = inbuf; + char* outptr = outbuf; + + inbuf[0] = 'h'; + inbuf[1] = ASCII_MAX + 1; // not ascii + inbuf[2] = 'i'; + inbuf[3] = '\0'; + + + size_t result = iconv(cd, &inptr, &insize, &outptr, &outsize); + + if (result == (size_t)(-1)) { + int saved_errno = errno; // iconv_close() clobbers it + + if (_my_iconv_close(&cd) == FAILURE) { + printf("ERROR (iconv_close)\n"); + } + else { + printf("FAIL (errno=%d)\n", saved_errno); + } + return FAILURE; + } + + if (strcmp(outbuf, "hi") != 0) { + printf("FAIL (outbuf=%s)\n", outbuf); + return FAILURE; + } + printf("OK (no error)\n"); + return SUCCESS; +} + int main(int argc, char** argv) { - int result = test_open_close(); + int result = SUCCESS; /* These three are named explicitly by POSIX which says that you are * free to append them to the destination codeset, but support is * not guaranteed; iconv_open() is allowed to fail with an EINVAL - * to indicate an unsupported suffix. */ - result |= test_iconv_open_supports_suffix("//IGNORE"); - result |= test_iconv_open_supports_suffix("//NON_IDENTICAL_DISCARD"); - result |= test_iconv_open_supports_suffix("//TRANSLIT"); + * to indicate an unsupported suffix. + * + * We also need to keep track of whether or not these indicator + * suffixes are supported. If they work at all, then the iconv() + * spec imposes some conditions on the implementation. */ + int ignore = test_iconv_open_supports_suffix("//IGNORE"); + int non_identical_discard = test_iconv_open_supports_suffix("//NON_IDENTICAL_DISCARD"); + int translit = test_iconv_open_supports_suffix("//TRANSLIT"); + result |= ignore | non_identical_discard | translit; /* The supported codeset names and suffixes are implementation- * defined, making this a bit ambiguous, but POSIX declares EINVAL @@ -379,5 +417,21 @@ int main(int argc, char** argv) { result |= test_iconv_too_big_is_e2big(); result |= test_iconv_incomplete_multibyte_is_einval(); + if (ignore == SUCCESS) { + result |= test_iconv_ignore_ignores_invalid(); + //result |= test_iconv_ignore_ignores_untranslatable(); + //result |= test_iconv_ignore_does_not_ignore_incomplete_multibyte(); + } + + if (translit == SUCCESS) { + //result |= test_translit_does_not_fail_on_untranslatable(); + //result |= test_translit_fails_on_incomplete_multibyte(); + } + + if (non_identical_discard == SUCCESS) { + //result |= test_nid_drops_untranslatable(); + //result |= test_nid_fails_on_incomplete_multibyte(); + } + return result; }