/* Test of POSIX compatible vasnprintf() and asnprintf() functions. Copyright (C) 2007-2026 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* Written by Bruno Haible , 2007. */ #include #include "vasnprintf.h" #include #include #include #include #include "macros.h" int main (int argc, char *argv[]) { /* configure should already have checked that the locale is supported. */ if (setlocale (LC_ALL, "") == NULL) return 1; /* Test that a locale dependent decimal point is used. */ { size_t length; char *result = asnprintf (NULL, &length, "%.1a", 1.0); ASSERT (result != NULL); ASSERT (streq (result, "0x1,0p+0") || streq (result, "0x2,0p-1") || streq (result, "0x4,0p-2") || streq (result, "0x8,0p-3")); ASSERT (length == strlen (result)); free (result); } /* Test that a locale dependent decimal point is used. */ { size_t length; char *result = asnprintf (NULL, &length, "%.1La", 1.0L); ASSERT (result != NULL); ASSERT (streq (result, "0x1,0p+0") || streq (result, "0x2,0p-1") || streq (result, "0x4,0p-2") || streq (result, "0x8,0p-3")); ASSERT (length == strlen (result)); free (result); } /* Test that a locale dependent grouping separator is used correctly. */ { const char *separator = localeconv ()->thousands_sep; /* = nl_langinfo (THOUSEP) */ size_t separator_len = strlen (separator); /* Tests of %d directive with grouping separator. */ { size_t length; char *result = asnprintf (NULL, &length, "%'d", 1000); ASSERT (result != NULL); ASSERT (length == 4 + separator_len); ASSERT (memeq (result, "1", 1) && memeq (result + 1, separator, separator_len) && streq (result + 1 + separator_len, "000")); free (result); } { size_t length; char *result = asnprintf (NULL, &length, "%'d", -1000); ASSERT (result != NULL); ASSERT (length == 5 + separator_len); ASSERT (memeq (result, "-1", 2) && memeq (result + 2, separator, separator_len) && streq (result + 2 + separator_len, "000")); free (result); } { size_t length; char *result = asnprintf (NULL, &length, "%'d", -142857); ASSERT (result != NULL); ASSERT (length == 7 + separator_len); ASSERT (memeq (result, "-142", 4) && memeq (result + 4, separator, separator_len) && streq (result + 4 + separator_len, "857")); free (result); } { size_t length; char *result = asnprintf (NULL, &length, "%'d", 2147483647); ASSERT (result != NULL); ASSERT (length == 10 + 3 * separator_len); ASSERT (memeq (result, "2", 1) && memeq (result + 1, separator, separator_len) && memeq (result + 1 + separator_len, "147", 3) && memeq (result + 4 + separator_len, separator, separator_len) && memeq (result + 4 + 2 * separator_len, "483", 3) && memeq (result + 7 + 2 * separator_len, separator, separator_len) && streq (result + 7 + 3 * separator_len, "647")); free (result); } { size_t length; char *result = asnprintf (NULL, &length, "%'d", -2147483647); ASSERT (result != NULL); ASSERT (length == 11 + 3 * separator_len); ASSERT (memeq (result, "-2", 2) && memeq (result + 2, separator, separator_len) && memeq (result + 2 + separator_len, "147", 3) && memeq (result + 5 + separator_len, separator, separator_len) && memeq (result + 5 + 2 * separator_len, "483", 3) && memeq (result + 8 + 2 * separator_len, separator, separator_len) && streq (result + 8 + 3 * separator_len, "647")); free (result); } { size_t length; char *result = asnprintf (NULL, &length, "%'.10d", 1000); ASSERT (result != NULL); if (length == 10 + separator_len) { /* Most implementations don't add the grouping character within the leading zeroes. */ ASSERT (length == 10 + separator_len); ASSERT (memeq (result, "0000001", 7) && memeq (result + 7, separator, separator_len) && streq (result + 7 + separator_len, "000")); } else { /* But there are good arguments for adding the grouping character within the leading zeroes. */ ASSERT (length == 10 + 3 * separator_len); ASSERT (memeq (result, "0", 1) && memeq (result + 1, separator, separator_len) && memeq (result + 1 + separator_len, "000", 3) && memeq (result + 4 + separator_len, separator, separator_len) && memeq (result + 4 + 2 * separator_len, "001", 3) && memeq (result + 7 + 2 * separator_len, separator, separator_len) && streq (result + 7 + 3 * separator_len, "000")); } free (result); } { size_t length; char *result = asnprintf (NULL, &length, "%'.10d", -1000); ASSERT (result != NULL); if (length == 11 + separator_len) { /* Most implementations don't add the grouping character within the leading zeroes. */ ASSERT (length == 11 + separator_len); ASSERT (memeq (result, "-0000001", 8) && memeq (result + 8, separator, separator_len) && streq (result + 8 + separator_len, "000")); } else { /* But there are good arguments for adding the grouping character within the leading zeroes. */ ASSERT (length == 11 + 3 * separator_len); ASSERT (memeq (result, "-0", 2) && memeq (result + 2, separator, separator_len) && memeq (result + 2 + separator_len, "000", 3) && memeq (result + 5 + separator_len, separator, separator_len) && memeq (result + 5 + 2 * separator_len, "001", 3) && memeq (result + 8 + 2 * separator_len, separator, separator_len) && streq (result + 8 + 3 * separator_len, "000")); } free (result); } { size_t length; char *result = asnprintf (NULL, &length, "%'10d", 1000); ASSERT (result != NULL); if (separator_len > 0) { if (length == 10) { /* Result according to POSIX, which says that the width is measured in "bytes". */ ASSERT (length == 10); ASSERT (memeq (result, " 1" + separator_len, 7 - separator_len) && memeq (result + 7 - separator_len, separator, separator_len) && streq (result + 7, "000")); } else { /* Result according to glibc, which measures the width in multibyte characters or column positions. */ ASSERT (length == 9 + separator_len); ASSERT (memeq (result, " 1", 6) && memeq (result + 6, separator, separator_len) && streq (result + 6 + separator_len, "000")); } } else { ASSERT (length == 10); ASSERT (streq (result, " 1000")); } free (result); } { size_t length; char *result = asnprintf (NULL, &length, "%'10d", -1000); ASSERT (result != NULL); if (separator_len > 0) { if (length == 10) { /* Result according to POSIX, which says that the width is measured in "bytes". */ ASSERT (length == 10); ASSERT (memeq (result, " -1" + separator_len, 7 - separator_len) && memeq (result + 7 - separator_len, separator, separator_len) && streq (result + 7, "000")); } else { /* Result according to glibc, which measures the width in multibyte characters or column positions. */ ASSERT (length == 9 + separator_len); ASSERT (memeq (result, " -1", 6) && memeq (result + 6, separator, separator_len) && streq (result + 6 + separator_len, "000")); } } else { ASSERT (length == 10); ASSERT (streq (result, " -1000")); } free (result); } /* Tests of %f directive with grouping separator. */ { size_t length; char *result = asnprintf (NULL, &length, "%'.0f", 1000.0); ASSERT (result != NULL); ASSERT (length == 4 + separator_len); ASSERT (memeq (result, "1", 1) && memeq (result + 1, separator, separator_len) && streq (result + 1 + separator_len, "000")); free (result); } { size_t length; char *result = asnprintf (NULL, &length, "%'.5f", 3141592653.5897932386); ASSERT (result != NULL); ASSERT (length == 16 + 3 * separator_len); ASSERT (memeq (result, "3", 1) && memeq (result + 1, separator, separator_len) && memeq (result + 1 + separator_len, "141", 3) && memeq (result + 4 + separator_len, separator, separator_len) && memeq (result + 4 + 2 * separator_len, "592", 3) && memeq (result + 7 + 2 * separator_len, separator, separator_len) && streq (result + 7 + 3 * separator_len, "653,58979")); free (result); } { size_t length; char *result = asnprintf (NULL, &length, "%'.5f", -3141592653.5897932386); ASSERT (result != NULL); ASSERT (length == 17 + 3 * separator_len); ASSERT (memeq (result, "-3", 2) && memeq (result + 2, separator, separator_len) && memeq (result + 2 + separator_len, "141", 3) && memeq (result + 5 + separator_len, separator, separator_len) && memeq (result + 5 + 2 * separator_len, "592", 3) && memeq (result + 8 + 2 * separator_len, separator, separator_len) && streq (result + 8 + 3 * separator_len, "653,58979")); free (result); } { size_t length; char *result = asnprintf (NULL, &length, "%'010.0f", 1000.0); ASSERT (result != NULL); if (separator_len > 0) { if (length == 10) { /* Result according to POSIX, which says that the width is measured in "bytes". */ ASSERT (length == 10); ASSERT (memeq (result, "0000001" + separator_len, 7 - separator_len) && memeq (result + 7 - separator_len, separator, separator_len) && streq (result + 7, "000")); } else { /* Result according to glibc, which measures the width in multibyte characters or column positions. */ ASSERT (length == 9 + separator_len); ASSERT (memeq (result, "000001", 6) && memeq (result + 6, separator, separator_len) && streq (result + 6 + separator_len, "000")); } } else { ASSERT (length == 10); ASSERT (streq (result, "0000001000")); } free (result); } /* Tests of %g directive with grouping separator. */ { size_t length; char *result = asnprintf (NULL, &length, "%'g", 1000.0); ASSERT (result != NULL); ASSERT (length == 4 + separator_len); ASSERT (memeq (result, "1", 1) && memeq (result + 1, separator, separator_len) && streq (result + 1 + separator_len, "000")); free (result); } { size_t length; char *result = asnprintf (NULL, &length, "%'g", -142857.0); ASSERT (result != NULL); ASSERT (length == 7 + separator_len); ASSERT (memeq (result, "-142", 4) && memeq (result + 4, separator, separator_len) && streq (result + 4 + separator_len, "857")); free (result); } { size_t length; char *result = asnprintf (NULL, &length, "%'.5g", 3141592653.5897932386); ASSERT (result != NULL); #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows uses 3 digits for the exponent. */ ASSERT (length == 11); ASSERT (streq (result, "3,1416e+009")); #else ASSERT (length == 10); ASSERT (streq (result, "3,1416e+09")); #endif free (result); } { size_t length; char *result = asnprintf (NULL, &length, "%'.5g", -3141592653.5897932386); ASSERT (result != NULL); #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows uses 3 digits for the exponent. */ ASSERT (length == 12); ASSERT (streq (result, "-3,1416e+009")); #else ASSERT (length == 11); ASSERT (streq (result, "-3,1416e+09")); #endif free (result); } { size_t length; char *result = asnprintf (NULL, &length, "%'.50g", 42351647362715016953416125033982098102569580078125.0); ASSERT (result != NULL); ASSERT (length == 50 + 16 * separator_len); ASSERT (memeq (result, "42", 2) && memeq (result + 2, separator, separator_len) && memeq (result + 2 + separator_len, "351", 3) && memeq (result + 5 + separator_len, separator, separator_len) && memeq (result + 5 + 2 * separator_len, "647", 3) && memeq (result + 8 + 2 * separator_len, separator, separator_len) && memeq (result + 8 + 3 * separator_len, "362", 3) && memeq (result + 11 + 3 * separator_len, separator, separator_len) && memeq (result + 11 + 4 * separator_len, "715", 3) && memeq (result + 14 + 4 * separator_len, separator, separator_len)); free (result); } { size_t length; char *result = asnprintf (NULL, &length, "%'010g", 1000.0); ASSERT (result != NULL); if (separator_len > 0) { if (length == 10) { /* Result according to POSIX, which says that the width is measured in "bytes". */ ASSERT (length == 10); ASSERT (memeq (result, "0000001" + separator_len, 7 - separator_len) && memeq (result + 7 - separator_len, separator, separator_len) && streq (result + 7, "000")); } else { /* Result according to glibc, which measures the width in multibyte characters or column positions. */ ASSERT (length == 9 + separator_len); ASSERT (memeq (result, "000001", 6) && memeq (result + 6, separator, separator_len) && streq (result + 6 + separator_len, "000")); } } else { ASSERT (length == 10); ASSERT (streq (result, "0000001000")); } free (result); } #if LDBL_MAX_10_EXP > 500 /* This test used to crash in the Solaris libc, for all Solaris versions. */ { size_t length; char *result = asnprintf (NULL, &length, "%'.500Lg\n", 42351647362715016953416125033982098102569580078125000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0L); free (result); } #endif } return test_exit_status; }