diff --git a/common/snprintf.c b/common/snprintf.c index d4898b5fc4..438829ce8f 100644 --- a/common/snprintf.c +++ b/common/snprintf.c @@ -53,10 +53,16 @@ #include "config.h" +#include #include #include #include +#ifdef TEST_SNPRINTF +extern int printf (const char *format, ...); +extern int sprintf (char *str, const char *format, ...); +#endif + #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) /* Define this as a fall through, HAVE_STDARG_H is probably already set */ @@ -112,7 +118,8 @@ static void dopr (char *buffer, size_t maxlen, const char *format, static void fmtstr (char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, int min, int max); static void fmtint (char *buffer, size_t *currlen, size_t maxlen, - long value, int base, int min, int max, int flags); + unsigned LLONG uvalue, int negative, + int base, int min, int max, int flags); static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, LDOUBLE fvalue, int min, int max, int flags); static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c ); @@ -169,6 +176,7 @@ static void dopr (char *buffer, size_t maxlen, const char *format, va_list args) { char ch; LLONG value; + unsigned LLONG uvalue; LDOUBLE fvalue; char *strvalue; int min; @@ -307,39 +315,40 @@ static void dopr (char *buffer, size_t maxlen, const char *format, va_list args) value = va_arg (args, LLONG); else value = va_arg (args, int); - fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); + fmtint (buffer, &currlen, maxlen, (unsigned LLONG)value, + (value < 0), 10, min, max, flags); break; case 'o': flags |= DP_F_UNSIGNED; if (cflags == DP_C_SHORT) #ifdef C89PLUS - value = (unsigned short int)va_arg (args, unsigned int); + uvalue = (unsigned short int)va_arg (args, unsigned int); #else - value = va_arg (args, unsigned short int); + uvalue = va_arg (args, unsigned short int); #endif else if (cflags == DP_C_LONG) - value = (long)va_arg (args, unsigned long int); + uvalue = va_arg (args, unsigned long int); else if (cflags == DP_C_LLONG) - value = (long)va_arg (args, unsigned LLONG); + uvalue = va_arg (args, unsigned LLONG); else - value = (long)va_arg (args, unsigned int); - fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags); + uvalue = va_arg (args, unsigned int); + fmtint (buffer, &currlen, maxlen, uvalue, 0, 8, min, max, flags); break; case 'u': flags |= DP_F_UNSIGNED; if (cflags == DP_C_SHORT) #ifdef C89PLUS - value = (unsigned short int)va_arg (args, unsigned int); + uvalue = (unsigned short int)va_arg (args, unsigned int); #else - value = va_arg (args, unsigned short int); + uvalue = va_arg (args, unsigned short int); #endif else if (cflags == DP_C_LONG) - value = (long)va_arg (args, unsigned long int); + uvalue = va_arg (args, unsigned long int); else if (cflags == DP_C_LLONG) - value = (LLONG)va_arg (args, unsigned LLONG); + uvalue = va_arg (args, unsigned LLONG); else - value = (long)va_arg (args, unsigned int); - fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); + uvalue = va_arg (args, unsigned int); + fmtint (buffer, &currlen, maxlen, uvalue, 0, 10, min, max, flags); break; case 'X': flags |= DP_F_UP; @@ -349,17 +358,17 @@ static void dopr (char *buffer, size_t maxlen, const char *format, va_list args) flags |= DP_F_UNSIGNED; if (cflags == DP_C_SHORT) #ifdef C89PLUS - value = (unsigned short int)va_arg (args, unsigned int); + uvalue = (unsigned short int)va_arg (args, unsigned int); #else - value = va_arg (args, unsigned short int); + uvalue = va_arg (args, unsigned short int); #endif else if (cflags == DP_C_LONG) - value = (long)va_arg (args, unsigned long int); + uvalue = va_arg (args, unsigned long int); else if (cflags == DP_C_LLONG) - value = (LLONG)va_arg (args, unsigned LLONG); + uvalue = va_arg (args, unsigned LLONG); else - value = (long)va_arg (args, unsigned int); - fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags); + uvalue = va_arg (args, unsigned int); + fmtint (buffer, &currlen, maxlen, uvalue, 0, 16, min, max, flags); break; case 'f': if (cflags == DP_C_LDOUBLE) @@ -400,13 +409,9 @@ static void dopr (char *buffer, size_t maxlen, const char *format, va_list args) break; case 'p': strvalue = va_arg (args, void *); - /* FIXME: in 64-bit (and Windows-targeted) builds this code yields: - * warning: cast from pointer to integer of different size - * so probably prints a truncated pointer value. Should check - * if sizeof(void*) == sizeof(long) and output e.g. two pieces - * (lower and upper long for bytes of the pointer). - */ - fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); + flags |= DP_F_UNSIGNED; + fmtint (buffer, &currlen, maxlen, + (unsigned LLONG)(size_t) strvalue, 0, 16, min, max, flags); break; case 'n': if (cflags == DP_C_SHORT) @@ -503,11 +508,11 @@ static void fmtstr (char *buffer, size_t *currlen, size_t maxlen, /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ static void fmtint (char *buffer, size_t *currlen, size_t maxlen, - long value, int base, int min, int max, int flags) + unsigned LLONG uvalue, int negative, + int base, int min, int max, int flags) { int signvalue = 0; - unsigned long uvalue; - char convert[20]; + char convert[sizeof(uvalue) * CHAR_BIT + 1]; int place = 0; int spadlen = 0; /* amount to space pad */ int zpadlen = 0; /* amount to zero pad */ @@ -516,13 +521,14 @@ static void fmtint (char *buffer, size_t *currlen, size_t maxlen, if (max < 0) max = 0; - uvalue = value; - if(!(flags & DP_F_UNSIGNED)) { - if( value < 0 ) { + if( negative ) { signvalue = '-'; - uvalue = -value; + /* uvalue holds the signed argument converted to unsigned + * (defined modulo arithmetic); unsigned negation yields its + * magnitude without overflow, even for LLONG_MIN. */ + uvalue = -uvalue; } else if (flags & DP_F_PLUS) /* Do a sign (+/i) */ @@ -539,8 +545,7 @@ static void fmtint (char *buffer, size_t *currlen, size_t maxlen, (caps? "0123456789ABCDEF":"0123456789abcdef") [uvalue % (unsigned)base ]; uvalue = (uvalue / (unsigned)base ); - } while(uvalue && (place < 20)); - if (place == 20) place--; + } while(uvalue && (place < (int)(sizeof(convert) - 1))); convert[place] = 0; zpadlen = max - place; @@ -942,6 +947,18 @@ static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c) NULL }; long int_nums[] = { -1, 134, 91340, 341, 0203, 0}; + static int pointer_num; +#ifdef HAVE_LONG_LONG_INT + LLONG llong_nums[] = { ((LLONG)1 << 32) + 1, LLONG_MIN }; + char *ullong_fmt[] = { "%llu", "%llx", "%llo", NULL }; + unsigned LLONG ullong_nums[] = { + ULLONG_MAX, + (unsigned LLONG)1 << (sizeof(unsigned LLONG) * CHAR_BIT - 1), + ULLONG_MAX + }; +#endif + char *ptr1; + char *ptr2; int x, y; int fail = 0; int num = 0; @@ -975,6 +992,81 @@ static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c) } num++; } + + snprintf (buf1, sizeof (buf1), "%u", UINT_MAX); + sprintf (buf2, "%u", UINT_MAX); + if (strcmp (buf1, buf2)) + { + printf("snprintf doesn't match Format: %%u\n\tsnprintf = %s\n\tsprintf = %s\n", + buf1, buf2); + fail++; + } + num++; + + snprintf (buf1, sizeof (buf1), "%lu", ULONG_MAX); + sprintf (buf2, "%lu", ULONG_MAX); + if (strcmp (buf1, buf2)) + { + printf("snprintf doesn't match Format: %%lu\n\tsnprintf = %s\n\tsprintf = %s\n", + buf1, buf2); + fail++; + } + num++; + + snprintf (buf1, sizeof (buf1), "%p", (void *)&pointer_num); + sprintf (buf2, "%p", (void *)&pointer_num); + ptr1 = buf1; + ptr2 = buf2; + if (ptr1[0] == '0' && (ptr1[1] == 'x' || ptr1[1] == 'X')) + ptr1 += 2; + if (ptr2[0] == '0' && (ptr2[1] == 'x' || ptr2[1] == 'X')) + ptr2 += 2; + while (ptr1[0] == '0' && ptr1[1] != '\0') + ptr1++; + while (ptr2[0] == '0' && ptr2[1] != '\0') + ptr2++; + while (*ptr1 && *ptr2 + && tolower ((unsigned char)*ptr1) == tolower ((unsigned char)*ptr2)) + { + ptr1++; + ptr2++; + } + if (*ptr1 || *ptr2) + { + printf("snprintf doesn't match Format: %%p\n\tsnprintf = %s\n\tsprintf = %s\n", + buf1, buf2); + fail++; + } + num++; + +#ifdef HAVE_LONG_LONG_INT + for (x = 0; x < 2; x++) + { + snprintf (buf1, sizeof (buf1), "%lld", llong_nums[x]); + sprintf (buf2, "%lld", llong_nums[x]); + if (strcmp (buf1, buf2)) + { + printf("snprintf doesn't match Format: %%lld\n\tsnprintf = %s\n\tsprintf = %s\n", + buf1, buf2); + fail++; + } + num++; + } + + for (x = 0; ullong_fmt[x] != NULL; x++) + { + snprintf (buf1, sizeof (buf1), ullong_fmt[x], ullong_nums[x]); + sprintf (buf2, ullong_fmt[x], ullong_nums[x]); + if (strcmp (buf1, buf2)) + { + printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n", + ullong_fmt[x], buf1, buf2); + fail++; + } + num++; + } +#endif printf ("%d tests failed out of %d.\n", fail, num); + return fail; } #endif /* SNPRINTF_TEST */