]> gitweb.michael.orlitzky.com - iconv-quirks.git/commitdiff
main.c: begin adding suffix tests, refactor...
authorMichael Orlitzky <michael@orlitzky.com>
Sun, 5 Jul 2026 18:00:46 +0000 (14:00 -0400)
committerMichael Orlitzky <michael@orlitzky.com>
Sun, 5 Jul 2026 18:00:46 +0000 (14:00 -0400)
main.c

diff --git a/main.c b/main.c
index c19c7e07a8fc7e98d6e1dd7b567d7914b357d867..dc4750036431876db322765d238a818610661564 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,7 +1,6 @@
 #include <errno.h>
 #include <iconv.h>
 #include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
 
 /* 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;
 }