Portability would be easy if each platform didn't have its own quirks. It turns out that the implementations of hexadecimal float printing in glibc <= 2.4 and MacOS X 10.3 are buggy. Both produce control characters in the output in some case: glibc sometimes outputs \001 and MacOS X sometimes outputs \377. This works around it.
2007-03-04 Bruno Haible <[EMAIL PROTECTED]> * m4/printf.m4 (gl_PRINTF_DIRECTIVE_A): Exclude two buggy implementations: glibc-2.4 and MacOS X 10.3. * tests/test-vasnprintf-posix.c (test_function): Test also the case that exhibits the bugs in glibc-2.4 and MacOS X 10.3. * tests/test-vasprintf-posix.c (test_function): Likewise. *** ./m4/printf.m4 4 Mar 2007 23:28:59 -0000 1.1 --- ./m4/printf.m4 5 Mar 2007 03:13:46 -0000 *************** *** 87,92 **** --- 87,93 ---- AC_DEFUN([gl_PRINTF_DIRECTIVE_A], [ AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([gt_TYPE_LONGDOUBLE]) AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles AC_CACHE_CHECK([whether printf supports the 'a' and 'A' directives], [gl_cv_func_printf_directive_a], *************** *** 98,121 **** int main () { if (sprintf (buf, "%a %d", 3.1416015625, 33, 44, 55) < 0 ! || strcmp (buf, "0x1.922p+1 33") != 0) return 1; if (sprintf (buf, "%A %d", -3.1416015625, 33, 44, 55) < 0 ! || strcmp (buf, "-0X1.922P+1 33") != 0) return 1; return 0; }], [gl_cv_func_printf_directive_a=yes], [gl_cv_func_printf_directive_a=no], [ - changequote(,)dnl case "$host_os" in ! dnl Guess yes on glibc systems. ! *-gnu*) gl_cv_func_printf_directive_a="guessing yes";; dnl Guess yes on FreeBSD >= 5. freebsd[1-4]*) gl_cv_func_printf_directive_a="guessing no";; freebsd* | kfreebsd*) gl_cv_func_printf_directive_a="guessing yes";; - dnl Gusss yes on MacOS X >= 10.3. - darwin[1-6].*) gl_cv_func_printf_directive_a="guessing no";; - darwin*) gl_cv_func_printf_directive_a="guessing yes";; dnl If we don't know, assume the worst. *) gl_cv_func_printf_directive_a="guessing no";; esac --- 99,153 ---- int main () { if (sprintf (buf, "%a %d", 3.1416015625, 33, 44, 55) < 0 ! || (strcmp (buf, "0x1.922p+1 33") != 0 ! && strcmp (buf, "0x3.244p+0 33") != 0 ! && strcmp (buf, "0x6.488p-1 33") != 0 ! && strcmp (buf, "0xc.91p-2 33") != 0)) return 1; if (sprintf (buf, "%A %d", -3.1416015625, 33, 44, 55) < 0 ! || (strcmp (buf, "-0X1.922P+1 33") != 0 ! && strcmp (buf, "-0X3.244P+0 33") != 0 ! && strcmp (buf, "-0X6.488P-1 33") != 0 ! && strcmp (buf, "-0XC.91P-2 33") != 0)) return 1; + /* This catches a MacOS X 10.3.9 (Darwin 7.9) bug. */ + if (sprintf (buf, "%.1a", 1.999) < 0 + || (strcmp (buf, "0x1.0p+1") != 0 + && strcmp (buf, "0x2.0p+0") != 0 + && strcmp (buf, "0x4.0p-1") != 0 + && strcmp (buf, "0x8.0p-2") != 0)) + return 1; + #if HAVE_LONG_DOUBLE + /* This catches the same MacOS X 10.3.9 (Darwin 7.9) bug and also a + glibc 2.4 bug <http://sourceware.org/bugzilla/show_bug.cgi?id=2908>. */ + if (sprintf (buf, "%.1La", 1.999L) < 0 + || (strcmp (buf, "0x1.0p+1") != 0 + && strcmp (buf, "0x2.0p+0") != 0 + && strcmp (buf, "0x4.0p-1") != 0 + && strcmp (buf, "0x8.0p-2") != 0)) + return 1; + #endif return 0; }], [gl_cv_func_printf_directive_a=yes], [gl_cv_func_printf_directive_a=no], [ case "$host_os" in ! dnl Guess yes on glibc >= 2.5 systems. ! *-gnu*) ! AC_EGREP_CPP([BZ2908], [ ! #include <features.h> ! #ifdef __GNU_LIBRARY__ ! #if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 5) || (__GLIBC__ > 2) ! BZ2908 ! #endif ! #endif ! ], ! [gl_cv_func_printf_directive_a="guessing yes"], ! [gl_cv_func_printf_directive_a="guessing no"]) ! ;; ! changequote(,)dnl dnl Guess yes on FreeBSD >= 5. freebsd[1-4]*) gl_cv_func_printf_directive_a="guessing no";; freebsd* | kfreebsd*) gl_cv_func_printf_directive_a="guessing yes";; dnl If we don't know, assume the worst. *) gl_cv_func_printf_directive_a="guessing no";; esac *************** *** 338,346 **** dnl . = yes, # = no. dnl dnl 1 2 3 4 5 6 7 ! dnl glibc 2.3.6 . . . . . . . dnl FreeBSD 5.4, 6.1 . . . . . . . ! dnl MacOS X 10.3.9 . . . . . . . dnl Cygwin 2007 . # . . . . . dnl Solaris 10 . # . . . . . dnl Solaris 2.6 ... 9 # # . . . . . --- 370,378 ---- dnl . = yes, # = no. dnl dnl 1 2 3 4 5 6 7 ! dnl glibc 2.3.6 . # . . . . . dnl FreeBSD 5.4, 6.1 . . . . . . . ! dnl MacOS X 10.3.9 . # . . . . . dnl Cygwin 2007 . # . . . . . dnl Solaris 10 . # . . . . . dnl Solaris 2.6 ... 9 # # . . . . . *** ./tests/test-vasnprintf-posix.c 4 Mar 2007 23:30:21 -0000 1.1 --- ./tests/test-vasnprintf-posix.c 5 Mar 2007 03:13:46 -0000 *************** *** 267,272 **** --- 267,286 ---- free (result); } + { /* Rounding can turn a ...FFF into a ...000. + This shows a MacOS X 10.3.9 (Darwin 7.9) bug. */ + size_t length; + char *result = + my_asnprintf (NULL, &length, "%.1a %d", 1.999, 33, 44, 55); + ASSERT (result != NULL); + ASSERT (strcmp (result, "0x1.0p+1 33") == 0 + || strcmp (result, "0x2.0p+0 33") == 0 + || strcmp (result, "0x4.0p-1 33") == 0 + || strcmp (result, "0x8.0p-2 33") == 0); + ASSERT (length == strlen (result)); + free (result); + } + { /* Width. */ size_t length; char *result = *************** *** 560,565 **** --- 574,594 ---- free (result); } + { /* Rounding can turn a ...FFF into a ...000. + This shows a MacOS X 10.3.9 (Darwin 7.9) bug and a + glibc 2.4 bug <http://sourceware.org/bugzilla/show_bug.cgi?id=2908>. */ + size_t length; + char *result = + my_asnprintf (NULL, &length, "%.1La %d", 1.999L, 33, 44, 55); + ASSERT (result != NULL); + ASSERT (strcmp (result, "0x1.0p+1 33") == 0 + || strcmp (result, "0x2.0p+0 33") == 0 + || strcmp (result, "0x4.0p-1 33") == 0 + || strcmp (result, "0x8.0p-2 33") == 0); + ASSERT (length == strlen (result)); + free (result); + } + { /* Width. */ size_t length; char *result = *** ./tests/test-vasprintf-posix.c 5 Mar 2007 00:39:01 -0000 1.1 --- ./tests/test-vasprintf-posix.c 5 Mar 2007 03:13:46 -0000 *************** *** 34,40 **** static void test_function (int (*my_asprintf) (char **, const char *, ...)) { - char buf[8]; int repeat; /* Test return value convention. */ --- 34,39 ---- *************** *** 250,255 **** --- 249,268 ---- free (result); } + { /* Rounding can turn a ...FFF into a ...000. + This shows a MacOS X 10.3.9 (Darwin 7.9) bug. */ + char *result; + int retval = + my_asprintf (&result, "%.1a %d", 1.999, 33, 44, 55); + ASSERT (result != NULL); + ASSERT (strcmp (result, "0x1.0p+1 33") == 0 + || strcmp (result, "0x2.0p+0 33") == 0 + || strcmp (result, "0x4.0p-1 33") == 0 + || strcmp (result, "0x8.0p-2 33") == 0); + ASSERT (retval == strlen (result)); + free (result); + } + { /* Width. */ char *result; int retval = *************** *** 543,548 **** --- 556,576 ---- free (result); } + { /* Rounding can turn a ...FFF into a ...000. + This shows a MacOS X 10.3.9 (Darwin 7.9) bug and a + glibc 2.4 bug <http://sourceware.org/bugzilla/show_bug.cgi?id=2908>. */ + char *result; + int retval = + my_asprintf (&result, "%.1La %d", 1.999L, 33, 44, 55); + ASSERT (result != NULL); + ASSERT (strcmp (result, "0x1.0p+1 33") == 0 + || strcmp (result, "0x2.0p+0 33") == 0 + || strcmp (result, "0x4.0p-1 33") == 0 + || strcmp (result, "0x8.0p-2 33") == 0); + ASSERT (retval == strlen (result)); + free (result); + } + { /* Width. */ char *result; int retval =