-#include <stdio.h>
#include <errno.h>
#include <iconv.h>
+#include <stdio.h>
+#include <string.h>
/* The various invalid sequences can be inferred from the table of
* valid ones,
* (d) 0xC0, 0xC1, 0xF5-0xFF are never valid
*/
-#define ICONV_OPEN_FAILED 1
-#define ICONV_CLOSE_FAILED 2
+#define SUCCESS 0
+#define FAILURE 1
-int main(int argc, char** argv) {
- const char* tocode = "UTF-8";
- const char* fromcode = "UTF-8";
-
- iconv_t cd = iconv_open(tocode, fromcode);
- if (cd == (iconv_t)(-1)) {
+/* Open a conversion descriptor by reference. Wraps the boilerplate
+ * error reporting when iconv_open() fails.
+ */
+int _my_iconv_open(iconv_t* cd, const char *tocode, const char *fromcode) {
+ *cd = iconv_open(tocode, fromcode);
+ if (*cd == (iconv_t)(-1)) {
/* The errno values are standard, but we have no way of knowing
* if the implementation follows the standard! */
fprintf(stderr,
fprintf(stderr, "EINVAL");
break;
default:
- fprintf(stderr, "UNKNOWN");
+ fprintf(stderr, "UNKNOWN (%d)", errno);
}
fprintf(stderr, "\n");
- return ICONV_OPEN_FAILED;
+ return FAILURE;
}
- /* actual conversion takes place here */
+ return SUCCESS;
+}
- if (iconv_close(cd) == -1) {
+/* Close a conversion descriptor by reference. Wraps the boilerplate
+ * error reporting when iconv_close() fails.
+ */
+int _my_iconv_close(iconv_t* cd) {
+ if (iconv_close(*cd) == -1) {
/* The underlying type of iconv_t is unspecified, so we can't
* easily print the argument here. */
fprintf(stderr, "ERROR: iconv_close() returned ");
fprintf(stderr, "EBADF");
break;
default:
- fprintf(stderr, "UNKNOWN");
+ fprintf(stderr, "UNKNOWN (%d)", errno);
}
fprintf(stderr, "\n");
- return ICONV_CLOSE_FAILED;
+ return FAILURE;
+ }
+
+ 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.
+ */
+int test_iconv_open_supports_suffix(const char* suffix) {
+ const char* fromcode = "ASCII";
+ char tocode[64] = "ASCII";
+ strcat(tocode, suffix);
+
+ printf("iconv_open() supports %s suffix...", suffix);
+ iconv_t cd = iconv_open(tocode, fromcode);
+ if (cd == (iconv_t)(-1)) {
+ switch (errno) {
+ case EINVAL:
+ printf("OK (EINVAL, not supported)\n");
+ return SUCCESS;
+ default:
+ printf("FAIL (errno=%d, unexpected error)\n", errno);
+ return FAILURE;
+ }
+ }
+ printf("yes\n");
+ iconv_close(cd);
+ return SUCCESS;
+}
+
+
+/*
+ * Check that iconv_open() fails with EINVAL when given a bogus
+ * indicator suffix.
+ */
+int test_iconv_open_does_not_support_invalid_suffix() {
+ const char* fromcode = "ASCII";
+ const char* tocode = "ASCII//INVALID";
+
+ printf("iconv_open() does not support //INVALID...");
+ iconv_t cd = iconv_open(tocode, fromcode);
+ if (cd == (iconv_t)(-1)) {
+ switch (errno) {
+ case EINVAL:
+ printf("OK (EINVAL, expected)\n");
+ return SUCCESS;
+ default:
+ printf("FAIL (errno=%d, unexpected)\n", errno);
+ return FAILURE;
+ }
}
+ printf("FAIL (invalid suffix was accepted)\n");
+ iconv_close(cd);
+ return FAILURE;
+}
+
+
+int test_iconv_open_does_not_support_invalid_to_codeset() {
+ const char* fromcode = "ASCII";
+ const char* tocode = "ASDJFI$@#%t234tWER";
+
+ printf("iconv_open() does not support invalid \"to\" codeset...");
+ iconv_t cd = iconv_open(tocode, fromcode);
+ if (cd == (iconv_t)(-1)) {
+ switch (errno) {
+ case EINVAL:
+ printf("OK (EINVAL, expected)\n");
+ return SUCCESS;
+ default:
+ printf("FAIL (errno=%d, unexpected)\n", errno);
+ return FAILURE;
+ }
+ }
+ printf("FAIL (invalid codeset was accepted)\n");
+ iconv_close(cd);
+ return FAILURE;
+}
+
+int test_iconv_open_does_not_support_invalid_from_codeset() {
+ const char* fromcode = "ASDJFI$@#%t234tWER";
+ const char* tocode = "ASCII";
+
+ printf("iconv_open() does not support invalid \"from\" codeset...");
+ iconv_t cd = iconv_open(tocode, fromcode);
+ if (cd == (iconv_t)(-1)) {
+ switch (errno) {
+ case EINVAL:
+ printf("OK (EINVAL, expected)\n");
+ return SUCCESS;
+ default:
+ printf("FAIL (errno=%d, unexpected)\n", errno);
+ return FAILURE;
+ }
+ }
+ printf("FAIL (invalid codeset was accepted)\n");
+ iconv_close(cd);
+ return FAILURE;
+}
+
+int main(int argc, char** argv) {
+ int result = test_open_close();
+
+ /* 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");
+
+ /* The supported codeset names and suffixes are implementation-
+ * defined, making this a bit ambiguous, but POSIX declares EINVAL
+ * to be the error code associated with unrecognized or unsupported
+ * values. (This doesn't stop an implementation from "supporting"
+ * invalid values by ignoring them, but for now let's assume no one
+ * is doing that.) */
+ result |= test_iconv_open_does_not_support_invalid_suffix();
+ result |= test_iconv_open_does_not_support_invalid_to_codeset();
+ result |= test_iconv_open_does_not_support_invalid_from_codeset();
- return 0;
+ return result;
}