/* * Copyright Patrick Powell 1995 * This code is based on code written by Patrick Powell (papowell@astart.com) * It may be used for any purpose as long as this notice remains intact * on all source code distributions */ /************************************************************** * Original: * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 * A bombproof version of doprnt (dopr) included. * Sigh. This sort of thing is always nasty do deal with. Note that * the version here does not include floating point... * * snprintf() is used instead of sprintf() as it does limit checks * for string length. This covers a nasty loophole. * * The other functions are there to prevent NULL pointers from * causing nasty effects. * * More Recently: * Brandon Long 9/15/96 for mutt 0.43 * This was ugly. It is still ugly. I opted out of floating point * numbers, but the formatter understands just about everything * from the normal C string format, at least as far as I can tell from * the Solaris 2.5 printf(3S) man page. * * Brandon Long 10/22/97 for mutt 0.87.1 * Ok, added some minimal floating point support, which means this * probably requires libm on most operating systems. Don't yet * support the exponent (e,E) and sigfig (g,G). Also, fmtint() * was pretty badly broken, it just wasn't being exercised in ways * which showed it, so that's been fixed. Also, formated the code * to mutt conventions, and removed dead code left over from the * original. Also, there is now a builtin-test, just compile with: * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm * and run snprintf for results. * * Thomas Roessler 01/27/98 for mutt 0.89i * The PGP code was using unsigned hexadecimal formats. * Unfortunately, unsigned formats simply didn't work. * * Michael Elkins 03/05/98 for mutt 0.90.8 * The original code assumed that both snprintf() and vsnprintf() were * missing. Some systems only have snprintf() but not vsnprintf(), so * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. * * Andrew Tridgell (tridge@samba.org) Oct 1998 * fixed handling of %.0f * added test for HAVE_LONG_DOUBLE * * raf (raf@raf.org) Sep 2001 * improved speed of %[diouxXp] * fixed handling of %# * fixed handling of %[feEgG] * fixed return value (required length, not truncated length) * fixed error reporting (return -1 on format error) * fixed snprintf(NULL, 0, "") * added manpage in pod format (perldoc -F snprintf.c) * added rigorous testing * fixed handling of %9.[diouxXp] * fixed handling of %p * fixed handling of flags [+- #0] * fixed handling of precision (%[diouxXps]) * fixed handling of field width (%c) * fixed handling of %h[diouxX] (bigendian) * added ability to mimic glibc or solaris behaviour * now ISO C 89 compliant formatting except fmt is not an mbstr * **************************************************************/ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include "snprintf.h" #define snprintf _p_snprintf #define vsnprintf _p_vsnprintf #ifdef HAVE_LONG_DOUBLE #define LDOUBLE long double #else #define LDOUBLE double #endif /* =head1 NAME I - safe sprintf =head1 SYNOPSIS #include int snprintf(char *str, size_t size, const char *fmt, ...); int vsnprintf(char *str, size_t size, const char *fmt, va_list args); =head1 DESCRIPTION Safe version of I of that doesn't suffer from buffer overruns. =over 4 =cut */ #ifndef TEST #if defined __STDC__ || defined __cplusplus #include #else #include #endif #ifdef HAVE_SPRINTF # if defined __STDC__ || defined __cplusplus int sprintf(char *str, const char *format, ...); # else int sprintf(); # endif #else # error "Missing sprintf() implementation! This should never happen!" #endif /* Format read states */ #define PARSE_DEFAULT 0 #define PARSE_FLAGS 1 #define PARSE_WIDTH 2 #define PARSE_DOT 3 #define PARSE_PRECISION 4 #define PARSE_SIZE 5 #define PARSE_CONVERSION 6 #define PARSE_DONE 7 /* Format flags */ #define FLAG_MINUS (1 << 0) #define FLAG_PLUS (1 << 1) #define FLAG_SPACE (1 << 2) #define FLAG_ALT (1 << 3) #define FLAG_ZERO (1 << 4) #define FLAG_UP (1 << 5) #define FLAG_UNSIGNED (1 << 6) #define FLAG_F (1 << 7) #define FLAG_E (1 << 8) #define FLAG_G (1 << 9) #define FLAG_PTR_SIGNED (1 << 10) #define FLAG_PTR_NIL (1 << 11) #define FLAG_PTR_NOALT (1 << 12) /* Conversion flags */ #define SIZE_SHORT 1 #define SIZE_LONG 2 #define SIZE_LDOUBLE 3 #ifndef max #define max(a, b) ((a >= b) ? a : b) #endif /* =item C Writes output to the string C, under control of the format string C, that specifies how subsequent arguments are converted for output. It is similar to I, except that C specifies the maximum number of characters to produce. The trailing C character is counted towards this limit, so you must allocate at least C characters for C. If C is zero, nothing is written and C may be C. Otherwise, output characters beyond the Cst are discarded rather than being written to C, and a C character is written at the end of the characters actually written to C. If copying takes place between objects that overlap, the behaviour is undefined. On success, returns the number of characters that would have been written had C been sufficiently large, not counting the terminating C character. Thus, the C-terminated output has been completely written if and only if the return value is nonnegative and less than C. On error, returns C<-1> (i.e. encoding error). Note that if your system already has I but this implementation was installed anyway, it's because the system implementation has a broken return value. Some older implementations (e.g. I) return C<-1> when the string is truncated rather than returning the number of characters that would have been written had C been sufficiently large (not counting the terminating C character) as required by I. =cut */ #ifndef HAVE_SNPRINTF #ifdef __STDC__ int snprintf(char *str, size_t size, const char *fmt, ...) #else int snprintf(str, size, fmt, va_alist) char *str; size_t size; const char *fmt; va_dcl #endif { int ret; va_list args; #ifdef __STDC__ va_start(args, fmt); #else va_start(args); #endif ret = vsnprintf(str, size, fmt, args); va_end(args); return ret; } #endif /* =item C Equivalent to I with the variable argument list specified directly as for I. =cut */ #if ! defined(HAVE_VSNPRINTF) || ! defined(HAVE_VSNPRINTF_C99) static void outch(char *buffer, size_t *currlen, size_t *reqlen, size_t size, int c) { if (*currlen + 1 < size) buffer[(*currlen)++] = (char)c; ++*reqlen; } static void fmtch(char *buffer, size_t *currlen, size_t *reqlen, size_t size, int value, int flags, int width) { int padlen; /* ** A negative field width argument is taken as a - flag followed by a ** positive field width argument */ if (width < 0) { flags |= FLAG_MINUS; width = -width; } padlen = width - 1; if (padlen < 0) padlen = 0; if (flags & FLAG_MINUS) padlen = -padlen; while (padlen > 0) { outch(buffer, currlen, reqlen, size, ' '); --padlen; } outch(buffer, currlen, reqlen, size, (unsigned int)value); while (padlen < 0) { outch(buffer, currlen, reqlen, size, ' '); ++padlen; } } static void fmtstr(char *buffer, size_t *currlen, size_t *reqlen, size_t size, char *value, int flags, int width, int precision) { int padlen, bytes; int cnt = 0; /* ** A negative field width argument is taken as a - flag followed by a ** positive field width argument */ if (width < 0) { flags |= FLAG_MINUS; width = -width; } /* A negative precision argument is taken as if the precision were ** omitted */ if (precision < 0) precision = -1; #ifdef HAVE_PRINTF_STR_FMT_NULL /* Print NULL as "(null)" if possible, otherwise as "" (like glibc) */ if (value == NULL) value = (precision == -1 || precision >= 6) ? "(null)" : ""; #endif for (bytes = 0; (precision == -1 || bytes < precision) && value[bytes]; ++bytes) {} padlen = width - bytes; if (padlen < 0) padlen = 0; if (flags & FLAG_MINUS) padlen = -padlen; while (padlen > 0) { outch(buffer, currlen, reqlen, size, ' '); --padlen; } while (*value && (precision == -1 || (cnt < precision))) { outch(buffer, currlen, reqlen, size, *value++); ++cnt; } while (padlen < 0) { outch(buffer, currlen, reqlen, size, ' '); ++padlen; } } static void fmtint(char *buffer, size_t *currlen, size_t *reqlen, size_t size, long value, int base, int width, int precision, int flags) { int signvalue = 0; unsigned long uvalue; unsigned char convert[22]; int place = 0; int spadlen = 0; int zpadlen = 0; const char *digits; int zextra = 0; int sextra = 0; /* ** A negative field width argument is taken as a - flag followed by a ** positive field width argument */ if (width < 0) { #ifdef HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR if (!(flags & FLAG_ZERO) || precision >= 0) #endif flags |= FLAG_MINUS; width = -width; } /* A negative precision argument is taken as if the precision were ** omitted */ if (precision < 0) precision = -1; /* If the space and + flags both appear, the space flag will be ignored */ if (flags & FLAG_PLUS) flags &= ~FLAG_SPACE; /* If the 0 and - flags both appear, the 0 flag will be ignored */ if (flags & FLAG_MINUS) flags &= ~FLAG_ZERO; /* If a precision is specified, the 0 flag will be ignored */ /* The d, i, o, u, x and X conversions have a default precision of 1 */ if (precision == -1) precision = 1; else flags &= ~FLAG_ZERO; /* ** The + flag: The result of the conversion will always begin with a plus ** or minus sign. (It will begin with a sign only when a negative value is ** converted if this flag is not specified.) ** ** The space flag: If the first character of a signed conversion is not a ** sign, or if a signed conversion results in no characters, a space will ** be prefixed to the result. */ uvalue = (unsigned long)value; if (!(flags & FLAG_UNSIGNED)) { if (value < 0) { signvalue = '-'; uvalue = (unsigned long)-value; } else if (flags & FLAG_PLUS) signvalue = '+'; else if (flags & FLAG_SPACE) signvalue = ' '; } #ifdef HAVE_PRINTF_PTR_FMT_SIGNED /* Behave like glibc (treat %p as signed (almost)) */ if (flags & FLAG_PTR_SIGNED && value) { if (flags & FLAG_PLUS) signvalue = '+'; else if (flags & FLAG_SPACE) signvalue = ' '; } #endif #ifdef HAVE_PRINTF_PTR_FMT_NOALT /* Behave like Solaris - %p never produces 0x */ if (flags & FLAG_PTR_NOALT) flags &= ~FLAG_ALT; #endif #ifdef HAVE_PRINTF_PTR_FMT_NIL if (flags & FLAG_PTR_NIL && !value) { spadlen = width - 5; if (spadlen < 0) spadlen = 0; if (flags & FLAG_MINUS) spadlen = -spadlen; while (spadlen > 0) { outch(buffer, currlen, reqlen, size, ' '); --spadlen; } outch(buffer, currlen, reqlen, size, '('); outch(buffer, currlen, reqlen, size, 'n'); outch(buffer, currlen, reqlen, size, 'i'); outch(buffer, currlen, reqlen, size, 'l'); outch(buffer, currlen, reqlen, size, ')'); while (spadlen < 0) { outch(buffer, currlen, reqlen, size, ' '); ++spadlen; } return; } #endif /* %[XEG] produce uppercase alpha characters */ digits = (flags & FLAG_UP) ? "0123456789ABCDEF" : "0123456789abcdef"; /* ** The result of converting a zero value with a precision of zero is no ** characters */ if (precision || uvalue) { do { convert[place++] = digits[uvalue % base]; uvalue /= base; } while (uvalue && (place < 21)); } convert[place] = 0; /* ** The # flag: For o conversion, it increases the precision to force the ** first digit of the result to be a zero. For x (or X) conversion, a ** non-zero result will have 0x (or 0X) prefixed to it. */ if (flags & FLAG_ALT) { if (base == 16 && value) sextra = 2; else if (base == 8 && precision <= place && (place == 0 || convert[place - 1] != '0')) zextra = 1; } /* ** The 0 flag: Leading zeroes (following any indication of sign or base) ** are used to pad to the field width; no space padding is performed. */ zpadlen = precision - place; if (zpadlen < 0) zpadlen = 0; zpadlen += zextra; spadlen = width - (place + zpadlen) - (signvalue ? 1 : 0) - sextra; if (spadlen < 0) spadlen = 0; if (flags & FLAG_ZERO) { zpadlen = max(zpadlen, spadlen); spadlen = 0; } if (flags & FLAG_MINUS) spadlen = -spadlen; while (spadlen > 0) { outch(buffer, currlen, reqlen, size, ' '); --spadlen; } if (signvalue) outch(buffer, currlen, reqlen, size, signvalue); if (flags & FLAG_ALT && base == 16 && sextra == 2) { outch(buffer, currlen, reqlen, size, '0'); outch(buffer, currlen, reqlen, size, (flags & FLAG_UP) ? 'X' : 'x'); } while (zpadlen > 0) { outch(buffer, currlen, reqlen, size, '0'); --zpadlen; } while (place > 0) outch(buffer, currlen, reqlen, size, convert[--place]); while (spadlen < 0) { outch(buffer, currlen, reqlen, size, ' '); ++spadlen; } } #ifndef DBL_MAX_10_EXP #define DBL_MAX_10_EXP 308 #endif #ifndef LDBL_MAX_10_EXP #define LDBL_MAX_10_EXP 4932 #endif #define DBL_MAX_EXP_DIGITS 3 #define LDBL_MAX_EXP_DIGITS 4 #define MAX_DIGITS(ldbl) \ ((ldbl) ? LDBL_MAX_10_EXP : DBL_MAX_10_EXP) #define MAX_EXP_DIGITS(ldbl) \ ((ldbl) ? LDBL_MAX_EXP_DIGITS : DBL_MAX_EXP_DIGITS) #define F_MAX(width, precision, ldbl) \ max((width), 1 + MAX_DIGITS(ldbl) + 1 + (precision)) #define E_MAX(width, precision, ldbl) \ max((width), 3 + (precision) + 2 + MAX_EXP_DIGITS(ldbl)) #define G_MAX(width, precision, ldbl) \ max(F_MAX((width), precision, ldbl), E_MAX((width), precision, ldbl)) static void fmtfp(char *buffer, size_t *currlen, size_t *reqlen, size_t size, LDOUBLE fvalue, int width, int precision, int flags, int cflags) { /* Calculate maximum space required and delegate to sprintf() */ char buf[512], *convert = buf, *p; char fmt[1 + 5 + 20 + 1 + 20 + 1 + 1 + 1]; char widstr[21]; int fpmax; /* ** A negative field width argument is taken as a - flag followed by a ** positive field width argument */ if (width < 0) { #ifdef HAVE_PRINTF_WITH_SOLARIS_NEGATIVE_WIDTH_BEHAVIOUR if ((flags & FLAG_ZERO) == 0) #endif flags |= FLAG_MINUS; width = -width; } /* ** A negative precision argument is taken as if the precision ** were omitted */ if (precision < 0) precision = -1; /* ** The ISO C standard (Section 7.9.6.2, The fscanf function), says that ** if the precision is missing, the default precision for f, e and E is ** taken to be 6. The default precision for g and G is taken to be 1. ** However, many systems use 6, so we'll provide an option. */ if (precision == -1) precision = #ifdef HAVE_PRINTF_FLT_FMT_G_STD (flags & FLAG_G) ? 1 : #endif 6; /* Calculate maximum possible length */ if (flags & FLAG_F) fpmax = F_MAX(width, precision, (cflags & SIZE_LDOUBLE)) + 1; else if (flags & FLAG_E) fpmax = E_MAX(width, precision, (cflags & SIZE_LDOUBLE)) + 1; else fpmax = G_MAX(width, precision, (cflags & SIZE_LDOUBLE)) + 1; /* Ensure enough space or bail out */ if (fpmax > 512 && !(convert = malloc(fpmax))) return; /* Build the format string (probably should have just copied it) */ sprintf(widstr, "%d", width); sprintf(fmt, "%%%s%s%s%s%s%s.%d%s%s", (flags & FLAG_MINUS) ? "-" : "", (flags & FLAG_PLUS) ? "+" : "", (flags & FLAG_SPACE) ? " " : "", (flags & FLAG_ALT) ? "#" : "", (flags & FLAG_ZERO) ? "0" : "", (width) ? widstr : "", precision, (cflags & SIZE_LDOUBLE) ? "L" : "", (flags & FLAG_E) ? (flags & FLAG_UP) ? "E" : "e" : (flags & FLAG_G) ? (flags & FLAG_UP) ? "G" : "g" : "f" ); /* Delegate to sprintf() */ if (cflags & SIZE_LDOUBLE) sprintf(convert, fmt, fvalue); else sprintf(convert, fmt, (double)fvalue); /* Copy to buffer */ for (p = convert; *p; ++p) outch(buffer, currlen, reqlen, size, *p); /* Deallocate if necessary */ if (convert != buf) free(convert); } int vsnprintf(char *str, size_t size, const char *fmt, va_list args) { char ch; long value; LDOUBLE fvalue; char *strvalue; int width; int precision; int state; int flags; int cflags; size_t currlen; size_t reqlen; state = PARSE_DEFAULT; currlen = reqlen = flags = cflags = width = 0; precision = -1; ch = *fmt++; while (state != PARSE_DONE) { if (ch == '\0') { if (state == PARSE_DEFAULT) state = PARSE_DONE; else return -1; } switch (state) { case PARSE_DEFAULT: if (ch == '%') state = PARSE_FLAGS; else outch(str, &currlen, &reqlen, size, ch); ch = *fmt++; break; case PARSE_FLAGS: switch (ch) { case '-': flags |= FLAG_MINUS; ch = *fmt++; break; case '+': flags |= FLAG_PLUS; ch = *fmt++; break; case ' ': flags |= FLAG_SPACE; ch = *fmt++; break; case '#': flags |= FLAG_ALT; ch = *fmt++; break; case '0': flags |= FLAG_ZERO; ch = *fmt++; break; default: state = PARSE_WIDTH; break; } break; case PARSE_WIDTH: if (isdigit((int)(unsigned char)ch)) { width = 10 * width + ch - '0'; ch = *fmt++; } else if (ch == '*') { width = va_arg(args, int); ch = *fmt++; state = PARSE_DOT; } else state = PARSE_DOT; break; case PARSE_DOT: if (ch == '.') { precision = 0; state = PARSE_PRECISION; ch = *fmt++; } else state = PARSE_SIZE; break; case PARSE_PRECISION: if (isdigit((int)(unsigned char)ch)) { precision = 10 * precision + ch - '0'; ch = *fmt++; } else if (ch == '*') { precision = va_arg(args, int); ch = *fmt++; state = PARSE_SIZE; } else state = PARSE_SIZE; break; case PARSE_SIZE: switch (ch) { case 'h': cflags = SIZE_SHORT; ch = *fmt++; break; case 'l': cflags = SIZE_LONG; ch = *fmt++; break; case 'L': cflags = SIZE_LDOUBLE; ch = *fmt++; break; } state = PARSE_CONVERSION; break; case PARSE_CONVERSION: switch (ch) { case 'd': case 'i': if (cflags == SIZE_SHORT) value = (short)va_arg(args, int); else if (cflags == SIZE_LONG) value = (long)va_arg(args, int); else value = (int)va_arg(args, int); fmtint(str, &currlen, &reqlen, size, value, 10, width, precision, flags); break; case 'o': flags |= FLAG_UNSIGNED; if (cflags == SIZE_SHORT) value = (unsigned short)va_arg(args, int); else if (cflags == SIZE_LONG) value = (unsigned long)va_arg(args, int); else value = (unsigned int)va_arg(args, int); fmtint(str, &currlen, &reqlen, size, value, 8, width, precision, flags); break; case 'u': flags |= FLAG_UNSIGNED; if (cflags == SIZE_SHORT) value = (unsigned short)va_arg(args, int); else if (cflags == SIZE_LONG) value = (unsigned long)va_arg(args, int); else value = (unsigned int)va_arg(args, int); fmtint(str, &currlen, &reqlen, size, value, 10, width, precision, flags); break; case 'X': flags |= FLAG_UP; case 'x': flags |= FLAG_UNSIGNED; if (cflags == SIZE_SHORT) value = (unsigned short)va_arg(args, int); else if (cflags == SIZE_LONG) value = (unsigned long)va_arg(args, int); else value = (unsigned int)va_arg(args, int); fmtint(str, &currlen, &reqlen, size, value, 16, width, precision, flags); break; case 'f': flags |= FLAG_F; if (cflags == SIZE_LDOUBLE) fvalue = va_arg(args, LDOUBLE); else fvalue = (LDOUBLE)va_arg(args, double); fmtfp(str, &currlen, &reqlen, size, fvalue, width, precision, flags, cflags); break; case 'E': flags |= FLAG_UP; case 'e': flags |= FLAG_E; if (cflags == SIZE_LDOUBLE) fvalue = va_arg(args, LDOUBLE); else fvalue = (LDOUBLE)va_arg(args, double); fmtfp(str, &currlen, &reqlen, size, fvalue, width, precision, flags, cflags); break; case 'G': flags |= FLAG_UP; case 'g': flags |= FLAG_G; if (cflags == SIZE_LDOUBLE) fvalue = va_arg(args, LDOUBLE); else fvalue = (LDOUBLE)va_arg(args, double); fmtfp(str, &currlen, &reqlen, size, fvalue, width, precision, flags, cflags); break; case 'c': fmtch(str, &currlen, &reqlen, size, va_arg(args, int), flags, width); break; case 's': strvalue = va_arg(args, char *); fmtstr(str, &currlen, &reqlen, size, strvalue, flags, width, precision); break; case 'p': flags |= FLAG_UNSIGNED; #ifdef HAVE_PRINTF_PTR_FMT_ALTERNATE flags |= FLAG_ALT; #endif #ifdef HAVE_PRINTF_PTR_FMT_SIGNED flags |= FLAG_PTR_SIGNED; #endif #ifdef HAVE_PRINTF_PTR_FMT_NIL flags |= FLAG_PTR_NIL; #endif #ifdef HAVE_PRINTF_PTR_FMT_NOALT flags |= FLAG_PTR_NOALT; #endif cflags = SIZE_LONG; strvalue = va_arg(args, void *); fmtint(str, &currlen, &reqlen, size, (long)strvalue, 16, width, precision, flags); break; case 'n': if (cflags == SIZE_SHORT) { short *num = va_arg(args, short *); *num = (short)currlen; } else if (cflags == SIZE_LONG) { long *num = va_arg(args, long *); *num = (long)currlen; } else { int *num = va_arg(args, int *); *num = currlen; } break; case '%': if (flags != 0 || cflags != 0 || width != 0 || precision != -1) return -1; outch(str, &currlen, &reqlen, size, ch); break; default: return -1; } ch = *fmt++; state = PARSE_DEFAULT; flags = cflags = width = 0; precision = -1; break; case PARSE_DONE: break; } } if (size) str[currlen] = '\0'; return reqlen; } #endif /* =back =head1 MT-Level MT-Safe - provided that the locale is only set by the main thread before starting any other threads. =head1 BUGS The format control string, C, should be interpreted as a multibyte character sequence but it is not. Apart from that, these functions comply with the ISO C 89 formatting requirements specified for the I function (section 7.9.6.1). Even though I is an ISO C 99 function (section 7.19.6.5), this implementation does not support the new ISO C 99 formatting conversions or length modifiers (i.e. C<%hh[diouxXn]>, C<%ll[diouxXn]>, C<%j[diouxXn]>, C<%z[diouxXn]>, C<%t[diouxXn]>, C<%ls>, C<%lc> and C<%[aAF]>). The main reason is that the local system's I function is used to perform floating point formatting. If the local system can support C<%[aA]>, then you must have C99 already and so you must also have I already. If I or I require more than 512 bytes of space in which to format a floating point number, but fail to allocate the required space, the floating point number will not be formatted at all and processing will continue. There is no indication to the client that an error occurred. The chances of this happening are remote. It would take a field width or precision greater than the available memory to trigger this bug. Since there are only 15 significant digits in a I and only 18 significant digits in am 80 bit I (33 significant digits in a 128 bit long double), a precision larger than 15/18/33 serves no purpose and a field width larger than the useful output serves no purpose. =head1 SEE ALSO L, L, L =head1 AUTHOR 20011109 raf , 1998 Andrew Tridgell , 1998 Michael Elkins , 1998 Thomas Roessler , 1996-1997 Brandon Long , 1995 Patrick Powell =cut */ #endif #ifdef TEST_SNPRINTF #define TEST #endif #ifdef TEST #include #ifndef LONG_STRING #define LONG_STRING (16 * 1024) #endif /* ** Note: I wanted to use 10000 (rather than 256) as the "huge" precision ** values in some of the floating point tests below. Under Linux, using ** 10000 worked fine, but under Solaris 2.6, even though we're using the ** system's own sprintf() function to render floating point numbers, 322 ** tests failed (badly). Even when the tests were modified to compare ** sprintf() with itself, 198 tests failed. Suffice to say that the Solaris' ** sprintf() is flaky. It can only handle precisions no greater than 260 ** (for double) and no greater than 508 (for long double). However, that's ** far greater than the actual number of significant digits in a double (15) ** or a long double (18 digits for 80 bit or 33 digits for 128 bit) so ** there's no problem. */ char *fp_fmt[] = { "%f", "%-f", "%+f", "% f", "%#f", "%0f", "%-+ #0f", "%9f", "%-9f", "%+9f", "% 9f", "%#9f", "%09f", "%-+ #09f", "%.9f", "%-.9f", "%+.9f", "% .9f", "%#.9f", "%0.9f", "%-+ #0.9f", "%9.f", "%-9.f", "%+9.f", "% 9.f", "%#9.f", "%09.f", "%-+ #09.f", "%9.9f", "%-9.9f", "%+9.9f", "% 9.9f", "%#9.9f", "%09.9f", "%-+ #09.9f", "%.0f", "%-.0f", "%+.0f", "% .0f", "%#.0f", "%0.0f", "%-+ #0.0f", "%.1f", "%-.1f", "%+.1f", "% .1f", "%#.1f", "%0.1f", "%-+ #0.1f", "%.256f", "%-.256f", "%+.256f", "% .256f", "%#.256f", "%0.256f", "%-+ #0.256f", "%10000f", "%-10000f", "%+10000f", "% 10000f", "%#10000f", "%010000f", "%-+ #010000f", "%10000.256f", "%-10000.256f", "%+10000.256f", "% 10000.256f", "%#10000.256f", "%010000.256f", "%-+ #010000.256f", "%e", "%-e", "%+e", "% e", "%#e", "%0e", "%-+ #0e", "%9e", "%-9e", "%+9e", "% 9e", "%#9e", "%09e", "%-+ #09e", "%.9e", "%-.9e", "%+.9e", "% .9e", "%#.9e", "%0.9e", "%-+ #0.9e", "%9.e", "%-9.e", "%+9.e", "% 9.e", "%#9.e", "%09.e", "%-+ #09.e", "%9.9e", "%-9.9e", "%+9.9e", "% 9.9e", "%#9.9e", "%09.9e", "%-+ #09.9e", "%.0e", "%-.0e", "%+.0e", "% .0e", "%#.0e", "%0.0e", "%-+ #0.0e", "%.1e", "%-.1e", "%+.1e", "% .1e", "%#.1e", "%0.1e", "%-+ #0.1e", "%.256e", "%-.256e", "%+.256e", "% .256e", "%#.256e", "%0.256e", "%-+ #0.256e", "%10000e", "%-10000e", "%+10000e", "% 10000e", "%#10000e", "%010000e", "%-+ #010000e", "%10000.256e", "%-10000.256e", "%+10000.256e", "% 10000.256e", "%#10000.256e", "%010000.256e", "%-+ #010000.256e", "%E", "%-E", "%+E", "% E", "%#E", "%0E", "%-+ #0E", "%9E", "%-9E", "%+9E", "% 9E", "%#9E", "%09E", "%-+ #09E", "%.9E", "%-.9E", "%+.9E", "% .9E", "%#.9E", "%0.9E", "%-+ #0.9E", "%9.E", "%-9.E", "%+9.E", "% 9.E", "%#9.E", "%09.E", "%-+ #09.E", "%9.9E", "%-9.9E", "%+9.9E", "% 9.9E", "%#9.9E", "%09.9E", "%-+ #09.9E", "%.0E", "%-.0E", "%+.0E", "% .0E", "%#.0E", "%0.0E", "%-+ #0.0E", "%.1E", "%-.1E", "%+.1E", "% .1E", "%#.1E", "%0.1E", "%-+ #0.1E", "%.256E", "%-.256E", "%+.256E", "% .256E", "%#.256E", "%0.256E", "%-+ #0.256E", "%10000E", "%-10000E", "%+10000E", "% 10000E", "%#10000E", "%010000E", "%-+ #010000E", "%10000.256E", "%-10000.256E", "%+10000.256E", "% 10000.256E", "%#10000.256E", "%010000.256E", "%-+ #010000.256E", "%g", "%-g", "%+g", "% g", "%#g", "%0g", "%-+ #0g", "%9g", "%-9g", "%+9g", "% 9g", "%#9g", "%09g", "%-+ #09g", "%.9g", "%-.9g", "%+.9g", "% .9g", "%#.9g", "%0.9g", "%-+ #0.9g", "%9.g", "%-9.g", "%+9.g", "% 9.g", "%#9.g", "%09.g", "%-+ #09.g", "%9.9g", "%-9.9g", "%+9.9g", "% 9.9g", "%#9.9g", "%09.9g", "%-+ #09.9g", "%.0g", "%-.0g", "%+.0g", "% .0g", "%#.0g", "%0.0g", "%-+ #0.0g", "%.1g", "%-.1g", "%+.1g", "% .1g", "%#.1g", "%0.1g", "%-+ #0.1g", "%.256g", "%-.256g", "%+.256g", "% .256g", "%#.256g", "%0.256g", "%-+ #0.256g", "%10000g", "%-10000g", "%+10000g", "% 10000g", "%#10000g", "%010000g", "%-+ #010000g", "%10000.256g", "%-10000.256g", "%+10000.256g", "% 10000.256g", "%#10000.256g", "%010000.256g", "%-+ #010000.256g", "%G", "%-G", "%+G", "% G", "%#G", "%0G", "%-+ #0G", "%9G", "%-9G", "%+9G", "% 9G", "%#9G", "%09G", "%-+ #09G", "%.9G", "%-.9G", "%+.9G", "% .9G", "%#.9G", "%0.9G", "%-+ #0.9G", "%9.G", "%-9.G", "%+9.G", "% 9.G", "%#9.G", "%09.G", "%-+ #09.G", "%9.9G", "%-9.9G", "%+9.9G", "% 9.9G", "%#9.9G", "%09.9G", "%-+ #09.9G", "%.0G", "%-.0G", "%+.0G", "% .0G", "%#.0G", "%0.0G", "%-+ #0.0G", "%.1G", "%-.1G", "%+.1G", "% .1G", "%#.1G", "%0.1G", "%-+ #0.1G", "%.256G", "%-.256G", "%+.256G", "% .256G", "%#.256G", "%0.256G", "%-+ #0.256G", "%10000G", "%-10000G", "%+10000G", "% 10000G", "%#10000G", "%010000G", "%-+ #010000G", "%10000.256G", "%-10000.256G", "%+10000.256G", "% 10000.256G", "%#10000.256G", "%010000.256G", "%-+ #010000.256G", "%-1.5f", "%1.5f", "%123.9f", "%10.5f", "% 10.5f", "%+22.9f", "%+4.9f", "%01.3f", "%4f", "%3.1f", "%3.2f", "%.0f", "%.1f", "%-1.5e", "%1.5e", "%123.9e", "%10.5e", "% 10.5e", "%+22.9e", "%+4.9e", "%01.3e", "%4e", "%3.1e", "%3.2e", "%.0e", "%.1e", "%-1.5E", "%1.5E", "%123.9E", "%10.5E", "% 10.5E", "%+22.9E", "%+4.9E", "%01.3E", "%4E", "%3.1E", "%3.2E", "%.0E", "%.1E", "%-1.5g", "%1.5g", "%123.9g", "%10.5g", "% 10.5g", "%+22.9g", "%+4.9g", "%01.3g", "%4g", "%3.1g", "%3.2g", "%.0g", "%.1g", "%-1.5G", "%1.5G", "%123.9G", "%10.5G", "% 10.5G", "%+22.9G", "%+4.9G", "%01.3G", "%4G", "%3.1G", "%3.2G", "%.0G", "%.1G", NULL }; char *fp_fmt2[] = { "%*f", "%-*f", "%+*f", "% *f", "%#*f", "%0*f", "%-+ #0*f", "%*.9f", "%-*.9f", "%+*.9f", "% *.9f", "%#*.9f", "%0*.9f", "%-+ #0*.9f", "%*e", "%-*e", "%+*e", "% *e", "%#*e", "%0*e", "%-+ #0*e", "%*.9e", "%-*.9e", "%+*.9e", "% *.9e", "%#*.9e", "%0*.9e", "%-+ #0*.9e", "%*E", "%-*E", "%+*E", "% *E", "%#*E", "%0*E", "%-+ #0*E", "%*.9E", "%-*.9E", "%+*.9E", "% *.9E", "%#*.9E", "%0*.9E", "%-+ #0*.9E", "%*g", "%-*g", "%+*g", "% *g", "%#*g", "%0*g", "%-+ #0*g", "%*.9g", "%-*.9g", "%+*.9g", "% *.9g", "%#*.9g", "%0*.9g", "%-+ #0*.9g", "%*G", "%-*G", "%+*G", "% *G", "%#*G", "%0*G", "%-+ #0*G", "%*.9G", "%-*.9G", "%+*.9G", "% *.9G", "%#*.9G", "%0*.9G", "%-+ #0*.9G", NULL }; char *fp_fmt3[] = { "%.*f", "%-.*f", "%+.*f", "% .*f", "%#.*f", "%0.*f", "%-+ #0.*f", "%9.*f", "%-9.*f", "%+9.*f", "% 9.*f", "%#9.*f", "%09.*f", "%-+ #09.*f", "%.*e", "%-.*e", "%+.*e", "% .*e", "%#.*e", "%0.*e", "%-+ #0.*e", "%9.*e", "%-9.*e", "%+9.*e", "% 9.*e", "%#9.*e", "%09.*e", "%-+ #09.*e", "%.*E", "%-.*E", "%+.*E", "% .*E", "%#.*E", "%0.*E", "%-+ #0.*E", "%9.*E", "%-9.*E", "%+9.*E", "% 9.*E", "%#9.*E", "%09.*E", "%-+ #09.*E", "%.*g", "%-.*g", "%+.*g", "% .*g", "%#.*g", "%0.*g", "%-+ #0.*g", "%9.*g", "%-9.*g", "%+9.*g", "% 9.*g", "%#9.*g", "%09.*g", "%-+ #09.*g", "%.*G", "%-.*G", "%+.*G", "% .*G", "%#.*G", "%0.*G", "%-+ #0.*G", "%9.*G", "%-9.*G", "%+9.*G", "% 9.*G", "%#9.*G", "%09.*G", "%-+ #09.*G", NULL }; char *fp_fmt4[] = { "%*.*f", "%-*.*f", "%+*.*f", "% *.*f", "%#*.*f", "%0*.*f", "%-+ #0*.*f", "%*.*e", "%-*.*e", "%+*.*e", "% *.*e", "%#*.*e", "%0*.*e", "%-+ #0*.*e", "%*.*E", "%-*.*E", "%+*.*E", "% *.*E", "%#*.*E", "%0*.*E", "%-+ #0*.*E", "%*.*g", "%-*.*g", "%+*.*g", "% *.*g", "%#*.*g", "%0*.*g", "%-+ #0*.*g", "%*.*G", "%-*.*G", "%+*.*G", "% *.*G", "%#*.*G", "%0*.*G", "%-+ #0*.*G", NULL }; char *fp_ldbl_fmt[] = { "%Lf", "%-Lf", "%+Lf", "% Lf", "%#Lf", "%0Lf", "%-+ #0Lf", "%9Lf", "%-9Lf", "%+9Lf", "% 9Lf", "%#9Lf", "%09Lf", "%-+ #09Lf", "%.9Lf", "%-.9Lf", "%+.9Lf", "% .9Lf", "%#.9Lf", "%0.9Lf", "%-+ #0.9Lf", "%9.Lf", "%-9.Lf", "%+9.Lf", "% 9.Lf", "%#9.Lf", "%09.Lf", "%-+ #09.Lf", "%9.9Lf", "%-9.9Lf", "%+9.9Lf", "% 9.9Lf", "%#9.9Lf", "%09.9Lf", "%-+ #09.9Lf", "%.0Lf", "%-.0Lf", "%+.0Lf", "% .0Lf", "%#.0Lf", "%0.0Lf", "%-+ #0.0Lf", "%.1Lf", "%-.1Lf", "%+.1Lf", "% .1Lf", "%#.1Lf", "%0.1Lf", "%-+ #0.1Lf", "%.256Lf", "%-.256Lf", "%+.256Lf", "% .256Lf", "%#.256Lf", "%0.256Lf", "%-+ #0.256Lf", "%10000Lf", "%-10000Lf", "%+10000Lf", "% 10000Lf", "%#10000Lf", "%010000Lf", "%-+ #010000Lf", "%10000.256Lf", "%-10000.256Lf", "%+10000.256Lf", "% 10000.256Lf", "%#10000.256Lf", "%010000.256Lf", "%-+ #010000.256Lf", "%Le", "%-Le", "%+Le", "% Le", "%#Le", "%0Le", "%-+ #0Le", "%9Le", "%-9Le", "%+9Le", "% 9Le", "%#9Le", "%09Le", "%-+ #09Le", "%.9Le", "%-.9Le", "%+.9Le", "% .9Le", "%#.9Le", "%0.9Le", "%-+ #0.9Le", "%9.Le", "%-9.Le", "%+9.Le", "% 9.Le", "%#9.Le", "%09.Le", "%-+ #09.Le", "%9.9Le", "%-9.9Le", "%+9.9Le", "% 9.9Le", "%#9.9Le", "%09.9Le", "%-+ #09.9Le", "%.0Le", "%-.0Le", "%+.0Le", "% .0Le", "%#.0Le", "%0.0Le", "%-+ #0.0Le", "%.1Le", "%-.1Le", "%+.1Le", "% .1Le", "%#.1Le", "%0.1Le", "%-+ #0.1Le", "%.256Le", "%-.256Le", "%+.256Le", "% .256Le", "%#.256Le", "%0.256Le", "%-+ #0.256Le", "%10000Le", "%-10000Le", "%+10000Le", "% 10000Le", "%#10000Le", "%010000Le", "%-+ #010000Le", "%10000.256Le", "%-10000.256Le", "%+10000.256Le", "% 10000.256Le", "%#10000.256Le", "%010000.256Le", "%-+ #010000.256Le", "%LE", "%-LE", "%+LE", "% LE", "%#LE", "%0LE", "%-+ #0LE", "%9LE", "%-9LE", "%+9LE", "% 9LE", "%#9LE", "%09LE", "%-+ #09LE", "%.9LE", "%-.9LE", "%+.9LE", "% .9LE", "%#.9LE", "%0.9LE", "%-+ #0.9LE", "%9.LE", "%-9.LE", "%+9.LE", "% 9.LE", "%#9.LE", "%09.LE", "%-+ #09.LE", "%9.9LE", "%-9.9LE", "%+9.9LE", "% 9.9LE", "%#9.9LE", "%09.9LE", "%-+ #09.9LE", "%.0LE", "%-.0LE", "%+.0LE", "% .0LE", "%#.0LE", "%0.0LE", "%-+ #0.0LE", "%.1LE", "%-.1LE", "%+.1LE", "% .1LE", "%#.1LE", "%0.1LE", "%-+ #0.1LE", "%.256LE", "%-.256LE", "%+.256LE", "% .256LE", "%#.256LE", "%0.256LE", "%-+ #0.256LE", "%10000LE", "%-10000LE", "%+10000LE", "% 10000LE", "%#10000LE", "%010000LE", "%-+ #010000LE", "%10000.256LE", "%-10000.256LE", "%+10000.256LE", "% 10000.256LE", "%#10000.256LE", "%010000.256LE", "%-+ #010000.256LE", "%Lg", "%-Lg", "%+Lg", "% Lg", "%#Lg", "%0Lg", "%-+ #0Lg", "%9Lg", "%-9Lg", "%+9Lg", "% 9Lg", "%#9Lg", "%09Lg", "%-+ #09Lg", "%.9Lg", "%-.9Lg", "%+.9Lg", "% .9Lg", "%#.9Lg", "%0.9Lg", "%-+ #0.9Lg", "%9.Lg", "%-9.Lg", "%+9.Lg", "% 9.Lg", "%#9.Lg", "%09.Lg", "%-+ #09.Lg", "%9.9Lg", "%-9.9Lg", "%+9.9Lg", "% 9.9Lg", "%#9.9Lg", "%09.9Lg", "%-+ #09.9Lg", "%.0Lg", "%-.0Lg", "%+.0Lg", "% .0Lg", "%#.0Lg", "%0.0Lg", "%-+ #0.0Lg", "%.1Lg", "%-.1Lg", "%+.1Lg", "% .1Lg", "%#.1Lg", "%0.1Lg", "%-+ #0.1Lg", "%.256Lg", "%-.256Lg", "%+.256Lg", "% .256Lg", "%#.256Lg", "%0.256Lg", "%-+ #0.256Lg", "%10000Lg", "%-10000Lg", "%+10000Lg", "% 10000Lg", "%#10000Lg", "%010000Lg", "%-+ #010000Lg", "%10000.256Lg", "%-10000.256Lg", "%+10000.256Lg", "% 10000.256Lg", "%#10000.256Lg", "%010000.256Lg", "%-+ #010000.256Lg", "%LG", "%-LG", "%+LG", "% LG", "%#LG", "%0LG", "%-+ #0LG", "%9LG", "%-9LG", "%+9LG", "% 9LG", "%#9LG", "%09LG", "%-+ #09LG", "%.9LG", "%-.9LG", "%+.9LG", "% .9LG", "%#.9LG", "%0.9LG", "%-+ #0.9LG", "%9.LG", "%-9.LG", "%+9.LG", "% 9.LG", "%#9.LG", "%09.LG", "%-+ #09.LG", "%9.9LG", "%-9.9LG", "%+9.9LG", "% 9.9LG", "%#9.9LG", "%09.9LG", "%-+ #09.9LG", "%.0LG", "%-.0LG", "%+.0LG", "% .0LG", "%#.0LG", "%0.0LG", "%-+ #0.0LG", "%.1LG", "%-.1LG", "%+.1LG", "% .1LG", "%#.1LG", "%0.1LG", "%-+ #0.1LG", "%.256LG", "%-.256LG", "%+.256LG", "% .256LG", "%#.256LG", "%0.256LG", "%-+ #0.256LG", "%10000LG", "%-10000LG", "%+10000LG", "% 10000LG", "%#10000LG", "%010000LG", "%-+ #010000LG", "%10000.256LG", "%-10000.256LG", "%+10000.256LG", "% 10000.256LG", "%#10000.256LG", "%010000.256LG", "%-+ #010000.256LG", "%-1.5Lf", "%1.5Lf", "%123.9Lf", "%10.5Lf", "% 10.5Lf", "%+22.9Lf", "%+4.9Lf", "%01.3Lf", "%4Lf", "%3.1Lf", "%3.2Lf", "%.0Lf", "%.1Lf", "%-1.5Le", "%1.5Le", "%123.9Le", "%10.5Le", "% 10.5Le", "%+22.9Le", "%+4.9Le", "%01.3Le", "%4Le", "%3.1Le", "%3.2Le", "%.0Le", "%.1Le", "%-1.5LE", "%1.5LE", "%123.9LE", "%10.5LE", "% 10.5LE", "%+22.9LE", "%+4.9LE", "%01.3LE", "%4LE", "%3.1LE", "%3.2LE", "%.0LE", "%.1LE", "%-1.5Lg", "%1.5Lg", "%123.9Lg", "%10.5Lg", "% 10.5Lg", "%+22.9Lg", "%+4.9Lg", "%01.3Lg", "%4Lg", "%3.1Lg", "%3.2Lg", "%.0Lg", "%.1Lg", "%-1.5LG", "%1.5LG", "%123.9LG", "%10.5LG", "% 10.5LG", "%+22.9LG", "%+4.9LG", "%01.3LG", "%4LG", "%3.1LG", "%3.2LG", "%.0LG", "%.1LG", NULL }; char *fp_ldbl_fmt2[] = { "%*Lf", "%-*Lf", "%+*Lf", "% *Lf", "%#*Lf", "%0*Lf", "%-+ #0*Lf", "%*Le", "%-*Le", "%+*Le", "% *Le", "%#*Le", "%0*Le", "%-+ #0*Le", "%*LE", "%-*LE", "%+*LE", "% *LE", "%#*LE", "%0*LE", "%-+ #0*LE", "%*Lg", "%-*Lg", "%+*Lg", "% *Lg", "%#*Lg", "%0*Lg", "%-+ #0*Lg", "%*LG", "%-*LG", "%+*LG", "% *LG", "%#*LG", "%0*LG", "%-+ #0*LG", NULL }; char *fp_ldbl_fmt3[] = { "%.*Lf", "%-.*Lf", "%+.*Lf", "% .*Lf", "%#.*Lf", "%0.*Lf", "%-+ #0.*Lf", "%.*Le", "%-.*Le", "%+.*Le", "% .*Le", "%#.*Le", "%0.*Le", "%-+ #0.*Le", "%.*LE", "%-.*LE", "%+.*LE", "% .*LE", "%#.*LE", "%0.*LE", "%-+ #0.*LE", "%.*Lg", "%-.*Lg", "%+.*Lg", "% .*Lg", "%#.*Lg", "%0.*Lg", "%-+ #0.*Lg", "%.*LG", "%-.*LG", "%+.*LG", "% .*LG", "%#.*LG", "%0.*LG", "%-+ #0.*LG", NULL }; char *fp_ldbl_fmt4[] = { "%*.*Lf", "%-*.*Lf", "%+*.*Lf", "% *.*Lf", "%#*.*Lf", "%0*.*Lf", "%-+ #0*.*Lf", "%*.*Le", "%-*.*Le", "%+*.*Le", "% *.*Le", "%#*.*Le", "%0*.*Le", "%-+ #0*.*Le", "%*.*LE", "%-*.*LE", "%+*.*LE", "% *.*LE", "%#*.*LE", "%0*.*LE", "%-+ #0*.*LE", "%*.*Lg", "%-*.*Lg", "%+*.*Lg", "% *.*Lg", "%#*.*Lg", "%0*.*Lg", "%-+ #0*.*Lg", "%*.*LG", "%-*.*LG", "%+*.*LG", "% *.*LG", "%#*.*LG", "%0*.*LG", "%-+ #0*.*LG", NULL }; LDOUBLE fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996, 0.9996, 1.996, 4.136, 0, 1.5, -134.21, -91340.2, -341.1234, -0203.9, -0.96, -0.996, -0.9996, -1.996, -4.136, 1.5e-1, -1.5e+250, 203.452e-250 }; char *int_fmt[] = { "%d", "%-d", "%+d", "% d", "%#d", "%0d", "%-+ #0d", "%9d", "%-9d", "%+9d", "% 9d", "%#9d", "%09d", "%-+ #09d", "%.9d", "%-.9d", "%+.9d", "% .9d", "%#.9d", "%0.9d", "%-+ #0.9d", "%9.d", "%-9.d", "%+9.d", "% 9.d", "%#9.d", "%09.d", "%-+ #09.d", "%9.9d", "%-9.9d", "%+9.9d", "% 9.9d", "%#9.9d", "%09.9d", "%-+ #09.9d", "%.0d", "%-.0d", "%+.0d", "% .0d", "%#.0d", "%0.0d", "%-+ #0.0d", "%.1d", "%-.1d", "%+.1d", "% .1d", "%#.1d", "%0.1d", "%-+ #0.1d", "%.10000d", "%-.10000d", "%+.10000d", "% .10000d", "%#.10000d", "%0.10000d", "%-+ #0.10000d", "%10000d", "%-10000d", "%+10000d", "% 10000d", "%#10000d", "%010000d", "%-+ #010000d", "%10000.10000d", "%-10000.10000d", "%+10000.10000d", "% 10000.10000d", "%#10000.10000d", "%010000.10000d", "%-+ #010000.10000d", "%i", "%-i", "%+i", "% i", "%#i", "%0i", "%-+ #0i", "%9i", "%-9i", "%+9i", "% 9i", "%#9i", "%09i", "%-+ #09i", "%.9i", "%-.9i", "%+.9i", "% .9i", "%#.9i", "%0.9i", "%-+ #0.9i", "%9.i", "%-9.i", "%+9.i", "% 9.i", "%#9.i", "%09.i", "%-+ #09.i", "%9.9i", "%-9.9i", "%+9.9i", "% 9.9i", "%#9.9i", "%09.9i", "%-+ #09.9i", "%.0i", "%-.0i", "%+.0i", "% .0i", "%#.0i", "%0.0i", "%-+ #0.0i", "%.1i", "%-.1i", "%+.1i", "% .1i", "%#.1i", "%0.1i", "%-+ #0.1i", "%.10000i", "%-.10000i", "%+.10000i", "% .10000i", "%#.10000i", "%0.10000i", "%-+ #0.10000i", "%10000i", "%-10000i", "%+10000i", "% 10000i", "%#10000i", "%010000i", "%-+ #010000i", "%10000.10000i", "%-10000.10000i", "%+10000.10000i", "% 10000.10000i", "%#10000.10000i", "%010000.10000i", "%-+ #010000.10000i", "%-1.5d", "%1.5d", "%123.9d", "%5.5d", "%10.5d", "% 10.5d", "%+22.33d", "%01.3d", "%4d", "%-1.5i", "%1.5i", "%123.9i", "%5.5i", "%10.5i", "% 10.5i", "%+22.33i", "%01.3i", "%4i", NULL }; char *int_fmt2[] = { "%*d", "%-*d", "%+*d", "% *d", "%#*d", "%0*d", "%-+ #0*d", "%*i", "%-*i", "%+*i", "% *i", "%#*i", "%0*i", "%-+ #0*i", NULL }; char *int_fmt3[] = { "%.*d", "%-.*d", "%+.*d", "% .*d", "%#.*d", "%0.*d", "%-+ #0.*d", "%.*i", "%-.*i", "%+.*i", "% .*i", "%#.*i", "%0.*i", "%-+ #0.*i", NULL }; char *int_fmt4[] = { "%*.*d", "%-*.*d", "%+*.*d", "% *.*d", "%#*.*d", "%0*.*d", "%-+ #0*.*d", "%*.*i", "%-*.*i", "%+*.*i", "% *.*i", "%#*.*i", "%0*.*i", "%-+ #0*.*i", NULL }; char *hint_fmt[] = { "%hd", "%-hd", "%+hd", "% hd", "%#hd", "%0hd", "%-+ #0hd", "%9hd", "%-9hd", "%+9hd", "% 9hd", "%#9hd", "%09hd", "%-+ #09hd", "%.9hd", "%-.9hd", "%+.9hd", "% .9hd", "%#.9hd", "%0.9hd", "%-+ #0.9hd", "%9.hd", "%-9.hd", "%+9.hd", "% 9.hd", "%#9.hd", "%09.hd", "%-+ #09.hd", "%9.9hd", "%-9.9hd", "%+9.9hd", "% 9.9hd", "%#9.9hd", "%09.9hd", "%-+ #09.9hd", "%.0hd", "%-.0hd", "%+.0hd", "% .0hd", "%#.0hd", "%0.0hd", "%-+ #0.0hd", "%.1hd", "%-.1hd", "%+.1hd", "% .1hd", "%#.1hd", "%0.1hd", "%-+ #0.1hd", "%.10000hd", "%-.10000hd", "%+.10000hd", "% .10000hd", "%#.10000hd", "%0.10000hd", "%-+ #0.10000hd", "%10000hd", "%-10000hd", "%+10000hd", "% 10000hd", "%#10000hd", "%010000hd", "%-+ #010000hd", "%10000.10000hd", "%-10000.10000hd", "%+10000.10000hd", "% 10000.10000hd", "%#10000.10000hd", "%010000.10000hd", "%-+ #010000.10000hd", "%hi", "%-hi", "%+hi", "% hi", "%#hi", "%0hi", "%-+ #0hi", "%9hi", "%-9hi", "%+9hi", "% 9hi", "%#9hi", "%09hi", "%-+ #09hi", "%.9hi", "%-.9hi", "%+.9hi", "% .9hi", "%#.9hi", "%0.9hi", "%-+ #0.9hi", "%9.hi", "%-9.hi", "%+9.hi", "% 9.hi", "%#9.hi", "%09.hi", "%-+ #09.hi", "%9.9hi", "%-9.9hi", "%+9.9hi", "% 9.9hi", "%#9.9hi", "%09.9hi", "%-+ #09.9hi", "%.0hi", "%-.0hi", "%+.0hi", "% .0hi", "%#.0hi", "%0.0hi", "%-+ #0.0hi", "%.1hi", "%-.1hi", "%+.1hi", "% .1hi", "%#.1hi", "%0.1hi", "%-+ #0.1hi", "%.10000hi", "%-.10000hi", "%+.10000hi", "% .10000hi", "%#.10000hi", "%0.10000hi", "%-+ #0.10000hi", "%10000hi", "%-10000hi", "%+10000hi", "% 10000hi", "%#10000hi", "%010000hi", "%-+ #010000hi", "%10000.10000hi", "%-10000.10000hi", "%+10000.10000hi", "% 10000.10000hi", "%#10000.10000hi", "%010000.10000hi", "%-+ #010000.10000hi", "%-1.5hd", "%1.5hd", "%123.9hd", "%5.5hd", "%10.5hd", "% 10.5hd", "%+22.33hd", "%01.3hd", "%4hd", "%-1.5hi", "%1.5hi", "%123.9hi", "%5.5hi", "%10.5hi", "% 10.5hi", "%+22.33hi", "%01.3hi", "%4hi", NULL }; char *hint_fmt2[] = { "%*hd", "%-*hd", "%+*hd", "% *hd", "%#*hd", "%0*hd", "%-+ #0*hd", "%*hi", "%-*hi", "%+*hi", "% *hi", "%#*hi", "%0*hi", "%-+ #0*hi", NULL }; char *hint_fmt3[] = { "%.*hd", "%-.*hd", "%+.*hd", "% .*hd", "%#.*hd", "%0.*hd", "%-+ #0.*hd", "%.*hi", "%-.*hi", "%+.*hi", "% .*hi", "%#.*hi", "%0.*hi", "%-+ #0.*hi", NULL }; char *hint_fmt4[] = { "%*.*hd", "%-*.*hd", "%+*.*hd", "% *.*hd", "%#*.*hd", "%0*.*hd", "%-+ #0*.*hd", "%*.*hi", "%-*.*hi", "%+*.*hi", "% *.*hi", "%#*.*hi", "%0*.*hi", "%-+ #0*.*hi", NULL }; char *lint_fmt[] = { "%ld", "%-ld", "%+ld", "% ld", "%#ld", "%0ld", "%-+ #0ld", "%9ld", "%-9ld", "%+9ld", "% 9ld", "%#9ld", "%09ld", "%-+ #09ld", "%.9ld", "%-.9ld", "%+.9ld", "% .9ld", "%#.9ld", "%0.9ld", "%-+ #0.9ld", "%9.ld", "%-9.ld", "%+9.ld", "% 9.ld", "%#9.ld", "%09.ld", "%-+ #09.ld", "%9.9ld", "%-9.9ld", "%+9.9ld", "% 9.9ld", "%#9.9ld", "%09.9ld", "%-+ #09.9ld", "%.0ld", "%-.0ld", "%+.0ld", "% .0ld", "%#.0ld", "%0.0ld", "%-+ #0.0ld", "%.1ld", "%-.1ld", "%+.1ld", "% .1ld", "%#.1ld", "%0.1ld", "%-+ #0.1ld", "%.10000ld", "%-.10000ld", "%+.10000ld", "% .10000ld", "%#.10000ld", "%0.10000ld", "%-+ #0.10000ld", "%10000ld", "%-10000ld", "%+10000ld", "% 10000ld", "%#10000ld", "%010000ld", "%-+ #010000ld", "%10000.10000ld", "%-10000.10000ld", "%+10000.10000ld", "% 10000.10000ld", "%#10000.10000ld", "%010000.10000ld", "%-+ #010000.10000ld", "%li", "%-li", "%+li", "% li", "%#li", "%0li", "%-+ #0li", "%9li", "%-9li", "%+9li", "% 9li", "%#9li", "%09li", "%-+ #09li", "%.9li", "%-.9li", "%+.9li", "% .9li", "%#.9li", "%0.9li", "%-+ #0.9li", "%9.li", "%-9.li", "%+9.li", "% 9.li", "%#9.li", "%09.li", "%-+ #09.li", "%9.9li", "%-9.9li", "%+9.9li", "% 9.9li", "%#9.9li", "%09.9li", "%-+ #09.9li", "%.0li", "%-.0li", "%+.0li", "% .0li", "%#.0li", "%0.0li", "%-+ #0.0li", "%.1li", "%-.1li", "%+.1li", "% .1li", "%#.1li", "%0.1li", "%-+ #0.1li", "%.10000li", "%-.10000li", "%+.10000li", "% .10000li", "%#.10000li", "%0.10000li", "%-+ #0.10000li", "%10000li", "%-10000li", "%+10000li", "% 10000li", "%#10000li", "%010000li", "%-+ #010000li", "%10000.10000li", "%-10000.10000li", "%+10000.10000li", "% 10000.10000li", "%#10000.10000li", "%010000.10000li", "%-+ #010000.10000li", "%-1.5ld", "%1.5ld", "%123.9ld", "%5.5ld", "%10.5ld", "% 10.5ld", "%+22.33ld", "%01.3ld", "%4ld", "%-1.5li", "%1.5li", "%123.9li", "%5.5li", "%10.5li", "% 10.5li", "%+22.33li", "%01.3li", "%4li", NULL }; char *lint_fmt2[] = { "%*ld", "%-*ld", "%+*ld", "% *ld", "%#*ld", "%0*ld", "%-+ #0*ld", "%*li", "%-*li", "%+*li", "% *li", "%#*li", "%0*li", "%-+ #0*li", NULL }; char *lint_fmt3[] = { "%.*ld", "%-.*ld", "%+.*ld", "% .*ld", "%#.*ld", "%0.*ld", "%-+ #0.*ld", "%.*li", "%-.*li", "%+.*li", "% .*li", "%#.*li", "%0.*li", "%-+ #0.*li", NULL }; char *lint_fmt4[] = { "%*.*ld", "%-*.*ld", "%+*.*ld", "% *.*ld", "%#*.*ld", "%0*.*ld", "%-+ #0*.*ld", "%*.*li", "%-*.*li", "%+*.*li", "% *.*li", "%#*.*li", "%0*.*li", "%-+ #0*.*li", NULL }; long int_nums[] = { -1, 134, 91340, 341, 0203, 0, -12345 }; char *uint_fmt[] = { "%o", "%-o", "%+o", "% o", "%#o", "%0o", "%-+ #0o", "%9o", "%-9o", "%+9o", "% 9o", "%#9o", "%09o", "%-+ #09o", "%.9o", "%-.9o", "%+.9o", "% .9o", "%#.9o", "%0.9o", "%-+ #0.9o", "%9.o", "%-9.o", "%+9.o", "% 9.o", "%#9.o", "%09.o", "%-+ #09.o", "%9.9o", "%-9.9o", "%+9.9o", "% 9.9o", "%#9.9o", "%09.9o", "%-+ #09.9o", "%.0o", "%-.0o", "%+.0o", "% .0o", "%#.0o", "%0.0o", "%-+ #0.0o", "%.1o", "%-.1o", "%+.1o", "% .1o", "%#.1o", "%0.1o", "%-+ #0.1o", "%.10000o", "%-.10000o", "%+.10000o", "% .10000o", "%#.10000o", "%0.10000o", "%-+ #0.10000o", "%10000o", "%-10000o", "%+10000o", "% 10000o", "%#10000o", "%010000o", "%-+ #010000o", "%10000.10000o", "%-10000.10000o", "%+10000.10000o", "% 10000.10000o", "%#10000.10000o", "%010000.10000o", "%-+ #010000.10000o", "%u", "%-u", "%+u", "% u", "%#u", "%0u", "%-+ #0u", "%9u", "%-9u", "%+9u", "% 9u", "%#9u", "%09u", "%-+ #09u", "%.9u", "%-.9u", "%+.9u", "% .9u", "%#.9u", "%0.9u", "%-+ #0.9u", "%9.u", "%-9.u", "%+9.u", "% 9.u", "%#9.u", "%09.u", "%-+ #09.u", "%9.9u", "%-9.9u", "%+9.9u", "% 9.9u", "%#9.9u", "%09.9u", "%-+ #09.9u", "%.0u", "%-.0u", "%+.0u", "% .0u", "%#.0u", "%0.0u", "%-+ #0.0u", "%.1u", "%-.1u", "%+.1u", "% .1u", "%#.1u", "%0.1u", "%-+ #0.1u", "%.10000u", "%-.10000u", "%+.10000u", "% .10000u", "%#.10000u", "%0.10000u", "%-+ #0.10000u", "%10000u", "%-10000u", "%+10000u", "% 10000u", "%#10000u", "%010000u", "%-+ #010000u", "%10000.10000u", "%-10000.10000u", "%+10000.10000u", "% 10000.10000u", "%#10000.10000u", "%010000.10000u", "%-+ #010000.10000u", "%x", "%-x", "%+x", "% x", "%#x", "%0x", "%-+ #0x", "%9x", "%-9x", "%+9x", "% 9x", "%#9x", "%09x", "%-+ #09x", "%.9x", "%-.9x", "%+.9x", "% .9x", "%#.9x", "%0.9x", "%-+ #0.9x", "%9.x", "%-9.x", "%+9.x", "% 9.x", "%#9.x", "%09.x", "%-+ #09.x", "%9.9x", "%-9.9x", "%+9.9x", "% 9.9x", "%#9.9x", "%09.9x", "%-+ #09.9x", "%.0x", "%-.0x", "%+.0x", "% .0x", "%#.0x", "%0.0x", "%-+ #0.0x", "%.1x", "%-.1x", "%+.1x", "% .1x", "%#.1x", "%0.1x", "%-+ #0.1x", "%.10000x", "%-.10000x", "%+.10000x", "% .10000x", "%#.10000x", "%0.10000x", "%-+ #0.10000x", "%10000x", "%-10000x", "%+10000x", "% 10000x", "%#10000x", "%010000x", "%-+ #010000x", "%10000.10000x", "%-10000.10000x", "%+10000.10000x", "% 10000.10000x", "%#10000.10000x", "%010000.10000x", "%-+ #010000.10000x", "%X", "%-X", "%+X", "% X", "%#X", "%0X", "%-+ #0X", "%9X", "%-9X", "%+9X", "% 9X", "%#9X", "%09X", "%-+ #09X", "%.9X", "%-.9X", "%+.9X", "% .9X", "%#.9X", "%0.9X", "%-+ #0.9X", "%9.X", "%-9.X", "%+9.X", "% 9.X", "%#9.X", "%09.X", "%-+ #09.X", "%9.9X", "%-9.9X", "%+9.9X", "% 9.9X", "%#9.9X", "%09.9X", "%-+ #09.9X", "%.0X", "%-.0X", "%+.0X", "% .0X", "%#.0X", "%0.0X", "%-+ #0.0X", "%.1X", "%-.1X", "%+.1X", "% .1X", "%#.1X", "%0.1X", "%-+ #0.1X", "%.10000X", "%-.10000X", "%+.10000X", "% .10000X", "%#.10000X", "%0.10000X", "%-+ #0.10000X", "%10000X", "%-10000X", "%+10000X", "% 10000X", "%#10000X", "%010000X", "%-+ #010000X", "%10000.10000X", "%-10000.10000X", "%+10000.10000X", "% 10000.10000X", "%#10000.10000X", "%010000.10000X", "%-+ #010000.10000X", "%p", "%-p", "%+p", "% p", "%#p", "%0p", "%-+ #0p", "%9p", "%-9p", "%+9p", "% 9p", "%#9p", "%09p", "%-+ #09p", "%.9p", "%-.9p", "%+.9p", "% .9p", "%#.9p", "%0.9p", "%-+ #0.9p", "%9.p", "%-9.p", "%+9.p", "% 9.p", "%#9.p", "%09.p", "%-+ #09.p", "%9.9p", "%-9.9p", "%+9.9p", "% 9.9p", "%#9.9p", "%09.9p", "%-+ #09.9p", "%.0p", "%-.0p", "%+.0p", "% .0p", "%#.0p", "%0.0p", "%-+ #0.0p", "%.1p", "%-.1p", "%+.1p", "% .1p", "%#.1p", "%0.1p", "%-+ #0.1p", "%.10000p", "%-.10000p", "%+.10000p", "% .10000p", "%#.10000p", "%0.10000p", "%-+ #0.10000p", "%10000p", "%-10000p", "%+10000p", "% 10000p", "%#10000p", "%010000p", "%-+ #010000p", "%10000.10000p", "%-10000.10000p", "%+10000.10000p", "% 10000.10000p", "%#10000.10000p", "%010000.10000p", "%-+ #010000.10000p", "%-1.5o", "%1.5o", "%123.9o", "%5.5o", "%10.5o", "% 10.5o", "%+22.33o", "%01.3o", "%4o", "%-1.5u", "%1.5u", "%123.9u", "%5.5u", "%10.5u", "% 10.5u", "%+22.33u", "%01.3u", "%4u", "%-1.5x", "%1.5x", "%123.9x", "%5.5x", "%10.5x", "% 10.5x", "%+22.33x", "%01.3x", "%4x", "%-1.5X", "%1.5X", "%123.9X", "%5.5X", "%10.5X", "% 10.5X", "%+22.33X", "%01.3X", "%4X", "%-1.5p", "%1.5p", "%123.9p", "%5.5p", "%10.5p", "% 10.5p", "%+22.33p", "%01.3p", "%4p", NULL }; char *uint_fmt2[] = { "%*o", "%-*o", "%+*o", "% *o", "%#*o", "%0*o", "%-+ #0*o", "%*u", "%-*u", "%+*u", "% *u", "%#*u", "%0*u", "%-+ #0*u", "%*x", "%-*x", "%+*x", "% *x", "%#*x", "%0*x", "%-+ #0*x", "%*X", "%-*X", "%+*X", "% *X", "%#*X", "%0*X", "%-+ #0*X", "%*p", "%-*p", "%+*p", "% *p", "%#*p", "%0*p", "%-+ #0*p", NULL }; char *uint_fmt3[] = { "%.*o", "%-.*o", "%+.*o", "% .*o", "%#.*o", "%0.*o", "%-+ #0.*o", "%.*u", "%-.*u", "%+.*u", "% .*u", "%#.*u", "%0.*u", "%-+ #0.*u", "%.*x", "%-.*x", "%+.*x", "% .*x", "%#.*x", "%0.*x", "%-+ #0.*x", "%.*X", "%-.*X", "%+.*X", "% .*X", "%#.*X", "%0.*X", "%-+ #0.*X", "%.*p", "%-.*p", "%+.*p", "% .*p", "%#.*p", "%0.*p", "%-+ #0.*p", NULL }; char *uint_fmt4[] = { "%*.*o", "%-*.*o", "%+*.*o", "% *.*o", "%#*.*o", "%0*.*o", "%-+ #0*.*o", "%*.*u", "%-*.*u", "%+*.*u", "% *.*u", "%#*.*u", "%0*.*u", "%-+ #0*.*u", "%*.*x", "%-*.*x", "%+*.*x", "% *.*x", "%#*.*x", "%0*.*x", "%-+ #0*.*x", "%*.*X", "%-*.*X", "%+*.*X", "% *.*X", "%#*.*X", "%0*.*X", "%-+ #0*.*X", "%*.*p", "%-*.*p", "%+*.*p", "% *.*p", "%#*.*p", "%0*.*p", "%-+ #0*.*p", NULL }; char *huint_fmt[] = { "%ho", "%-ho", "%+ho", "% ho", "%#ho", "%0ho", "%-+ #0ho", "%9ho", "%-9ho", "%+9ho", "% 9ho", "%#9ho", "%09ho", "%-+ #09ho", "%.9ho", "%-.9ho", "%+.9ho", "% .9ho", "%#.9ho", "%0.9ho", "%-+ #0.9ho", "%9.ho", "%-9.ho", "%+9.ho", "% 9.ho", "%#9.ho", "%09.ho", "%-+ #09.ho", "%9.9ho", "%-9.9ho", "%+9.9ho", "% 9.9ho", "%#9.9ho", "%09.9ho", "%-+ #09.9ho", "%.0ho", "%-.0ho", "%+.0ho", "% .0ho", "%#.0ho", "%0.0ho", "%-+ #0.0ho", "%.1ho", "%-.1ho", "%+.1ho", "% .1ho", "%#.1ho", "%0.1ho", "%-+ #0.1ho", "%.10000ho", "%-.10000ho", "%+.10000ho", "% .10000ho", "%#.10000ho", "%0.10000ho", "%-+ #0.10000ho", "%10000ho", "%-10000ho", "%+10000ho", "% 10000ho", "%#10000ho", "%010000ho", "%-+ #010000ho", "%10000.10000ho", "%-10000.10000ho", "%+10000.10000ho", "% 10000.10000ho", "%#10000.10000ho", "%010000.10000ho", "%-+ #010000.10000ho", "%hu", "%-hu", "%+hu", "% hu", "%#hu", "%0hu", "%-+ #0hu", "%9hu", "%-9hu", "%+9hu", "% 9hu", "%#9hu", "%09hu", "%-+ #09hu", "%.9hu", "%-.9hu", "%+.9hu", "% .9hu", "%#.9hu", "%0.9hu", "%-+ #0.9hu", "%9.hu", "%-9.hu", "%+9.hu", "% 9.hu", "%#9.hu", "%09.hu", "%-+ #09.hu", "%9.9hu", "%-9.9hu", "%+9.9hu", "% 9.9hu", "%#9.9hu", "%09.9hu", "%-+ #09.9hu", "%.0hu", "%-.0hu", "%+.0hu", "% .0hu", "%#.0hu", "%0.0hu", "%-+ #0.0hu", "%.1hu", "%-.1hu", "%+.1hu", "% .1hu", "%#.1hu", "%0.1hu", "%-+ #0.1hu", "%.10000hu", "%-.10000hu", "%+.10000hu", "% .10000hu", "%#.10000hu", "%0.10000hu", "%-+ #0.10000hu", "%10000hu", "%-10000hu", "%+10000hu", "% 10000hu", "%#10000hu", "%010000hu", "%-+ #010000hu", "%10000.10000hu", "%-10000.10000hu", "%+10000.10000hu", "% 10000.10000hu", "%#10000.10000hu", "%010000.10000hu", "%-+ #010000.10000hu", "%hx", "%-hx", "%+hx", "% hx", "%#hx", "%0hx", "%-+ #0hx", "%9hx", "%-9hx", "%+9hx", "% 9hx", "%#9hx", "%09hx", "%-+ #09hx", "%.9hx", "%-.9hx", "%+.9hx", "% .9hx", "%#.9hx", "%0.9hx", "%-+ #0.9hx", "%9.hx", "%-9.hx", "%+9.hx", "% 9.hx", "%#9.hx", "%09.hx", "%-+ #09.hx", "%9.9hx", "%-9.9hx", "%+9.9hx", "% 9.9hx", "%#9.9hx", "%09.9hx", "%-+ #09.9hx", "%.0hx", "%-.0hx", "%+.0hx", "% .0hx", "%#.0hx", "%0.0hx", "%-+ #0.0hx", "%.1hx", "%-.1hx", "%+.1hx", "% .1hx", "%#.1hx", "%0.1hx", "%-+ #0.1hx", "%.10000hx", "%-.10000hx", "%+.10000hx", "% .10000hx", "%#.10000hx", "%0.10000hx", "%-+ #0.10000hx", "%10000hx", "%-10000hx", "%+10000hx", "% 10000hx", "%#10000hx", "%010000hx", "%-+ #010000hx", "%10000.10000hx", "%-10000.10000hx", "%+10000.10000hx", "% 10000.10000hx", "%#10000.10000hx", "%010000.10000hx", "%-+ #010000.10000hx", "%hX", "%-hX", "%+hX", "% hX", "%#hX", "%0hX", "%-+ #0hX", "%9hX", "%-9hX", "%+9hX", "% 9hX", "%#9hX", "%09hX", "%-+ #09hX", "%.9hX", "%-.9hX", "%+.9hX", "% .9hX", "%#.9hX", "%0.9hX", "%-+ #0.9hX", "%9.hX", "%-9.hX", "%+9.hX", "% 9.hX", "%#9.hX", "%09.hX", "%-+ #09.hX", "%9.9hX", "%-9.9hX", "%+9.9hX", "% 9.9hX", "%#9.9hX", "%09.9hX", "%-+ #09.9hX", "%.0hX", "%-.0hX", "%+.0hX", "% .0hX", "%#.0hX", "%0.0hX", "%-+ #0.0hX", "%.1hX", "%-.1hX", "%+.1hX", "% .1hX", "%#.1hX", "%0.1hX", "%-+ #0.1hX", "%.10000hX", "%-.10000hX", "%+.10000hX", "% .10000hX", "%#.10000hX", "%0.10000hX", "%-+ #0.10000hX", "%10000hX", "%-10000hX", "%+10000hX", "% 10000hX", "%#10000hX", "%010000hX", "%-+ #010000hX", "%10000.10000hX", "%-10000.10000hX", "%+10000.10000hX", "% 10000.10000hX", "%#10000.10000hX", "%010000.10000hX", "%-+ #010000.10000hX", "%-1.5ho", "%1.5ho", "%123.9ho", "%5.5ho", "%10.5ho", "% 10.5ho", "%+22.33ho", "%01.3ho", "%4ho", "%-1.5hu", "%1.5hu", "%123.9hu", "%5.5hu", "%10.5hu", "% 10.5hu", "%+22.33hu", "%01.3hu", "%4hu", "%-1.5hx", "%1.5hx", "%123.9hx", "%5.5hx", "%10.5hx", "% 10.5hx", "%+22.33hx", "%01.3hx", "%4hx", "%-1.5hX", "%1.5hX", "%123.9hX", "%5.5hX", "%10.5hX", "% 10.5hX", "%+22.33hX", "%01.3hX", "%4hX", NULL }; char *huint_fmt2[] = { "%*ho", "%-*ho", "%+*ho", "% *ho", "%#*ho", "%0*ho", "%-+ #0*ho", "%*hu", "%-*hu", "%+*hu", "% *hu", "%#*hu", "%0*hu", "%-+ #0*hu", "%*hx", "%-*hx", "%+*hx", "% *hx", "%#*hx", "%0*hx", "%-+ #0*hx", "%*hX", "%-*hX", "%+*hX", "% *hX", "%#*hX", "%0*hX", "%-+ #0*hX", NULL }; char *huint_fmt3[] = { "%.*ho", "%-.*ho", "%+.*ho", "% .*ho", "%#.*ho", "%0.*ho", "%-+ #0.*ho", "%.*hu", "%-.*hu", "%+.*hu", "% .*hu", "%#.*hu", "%0.*hu", "%-+ #0.*hu", "%.*hx", "%-.*hx", "%+.*hx", "% .*hx", "%#.*hx", "%0.*hx", "%-+ #0.*hx", "%.*hX", "%-.*hX", "%+.*hX", "% .*hX", "%#.*hX", "%0.*hX", "%-+ #0.*hX", NULL }; char *huint_fmt4[] = { "%*.*ho", "%-*.*ho", "%+*.*ho", "% *.*ho", "%#*.*ho", "%0*.*ho", "%-+ #0*.*ho", "%*.*hu", "%-*.*hu", "%+*.*hu", "% *.*hu", "%#*.*hu", "%0*.*hu", "%-+ #0*.*hu", "%*.*hx", "%-*.*hx", "%+*.*hx", "% *.*hx", "%#*.*hx", "%0*.*hx", "%-+ #0*.*hx", "%*.*hX", "%-*.*hX", "%+*.*hX", "% *.*hX", "%#*.*hX", "%0*.*hX", "%-+ #0*.*hX", NULL }; char *luint_fmt[] = { "%lo", "%-lo", "%+lo", "% lo", "%#lo", "%0lo", "%-+ #0lo", "%9lo", "%-9lo", "%+9lo", "% 9lo", "%#9lo", "%09lo", "%-+ #09lo", "%.9lo", "%-.9lo", "%+.9lo", "% .9lo", "%#.9lo", "%0.9lo", "%-+ #0.9lo", "%9.lo", "%-9.lo", "%+9.lo", "% 9.lo", "%#9.lo", "%09.lo", "%-+ #09.lo", "%9.9lo", "%-9.9lo", "%+9.9lo", "% 9.9lo", "%#9.9lo", "%09.9lo", "%-+ #09.9lo", "%.0lo", "%-.0lo", "%+.0lo", "% .0lo", "%#.0lo", "%0.0lo", "%-+ #0.0lo", "%.1lo", "%-.1lo", "%+.1lo", "% .1lo", "%#.1lo", "%0.1lo", "%-+ #0.1lo", "%.10000lo", "%-.10000lo", "%+.10000lo", "% .10000lo", "%#.10000lo", "%0.10000lo", "%-+ #0.10000lo", "%10000lo", "%-10000lo", "%+10000lo", "% 10000lo", "%#10000lo", "%010000lo", "%-+ #010000lo", "%10000.10000lo", "%-10000.10000lo", "%+10000.10000lo", "% 10000.10000lo", "%#10000.10000lo", "%010000.10000lo", "%-+ #010000.10000lo", "%lu", "%-lu", "%+lu", "% lu", "%#lu", "%0lu", "%-+ #0lu", "%9lu", "%-9lu", "%+9lu", "% 9lu", "%#9lu", "%09lu", "%-+ #09lu", "%.9lu", "%-.9lu", "%+.9lu", "% .9lu", "%#.9lu", "%0.9lu", "%-+ #0.9lu", "%9.lu", "%-9.lu", "%+9.lu", "% 9.lu", "%#9.lu", "%09.lu", "%-+ #09.lu", "%9.9lu", "%-9.9lu", "%+9.9lu", "% 9.9lu", "%#9.9lu", "%09.9lu", "%-+ #09.9lu", "%.0lu", "%-.0lu", "%+.0lu", "% .0lu", "%#.0lu", "%0.0lu", "%-+ #0.0lu", "%.1lu", "%-.1lu", "%+.1lu", "% .1lu", "%#.1lu", "%0.1lu", "%-+ #0.1lu", "%.10000lu", "%-.10000lu", "%+.10000lu", "% .10000lu", "%#.10000lu", "%0.10000lu", "%-+ #0.10000lu", "%10000lu", "%-10000lu", "%+10000lu", "% 10000lu", "%#10000lu", "%010000lu", "%-+ #010000lu", "%10000.10000lu", "%-10000.10000lu", "%+10000.10000lu", "% 10000.10000lu", "%#10000.10000lu", "%010000.10000lu", "%-+ #010000.10000lu", "%lx", "%-lx", "%+lx", "% lx", "%#lx", "%0lx", "%-+ #0lx", "%9lx", "%-9lx", "%+9lx", "% 9lx", "%#9lx", "%09lx", "%-+ #09lx", "%.9lx", "%-.9lx", "%+.9lx", "% .9lx", "%#.9lx", "%0.9lx", "%-+ #0.9lx", "%9.lx", "%-9.lx", "%+9.lx", "% 9.lx", "%#9.lx", "%09.lx", "%-+ #09.lx", "%9.9lx", "%-9.9lx", "%+9.9lx", "% 9.9lx", "%#9.9lx", "%09.9lx", "%-+ #09.9lx", "%.0lx", "%-.0lx", "%+.0lx", "% .0lx", "%#.0lx", "%0.0lx", "%-+ #0.0lx", "%.1lx", "%-.1lx", "%+.1lx", "% .1lx", "%#.1lx", "%0.1lx", "%-+ #0.1lx", "%.10000lx", "%-.10000lx", "%+.10000lx", "% .10000lx", "%#.10000lx", "%0.10000lx", "%-+ #0.10000lx", "%10000lx", "%-10000lx", "%+10000lx", "% 10000lx", "%#10000lx", "%010000lx", "%-+ #010000lx", "%10000.10000lx", "%-10000.10000lx", "%+10000.10000lx", "% 10000.10000lx", "%#10000.10000lx", "%010000.10000lx", "%-+ #010000.10000lx", "%lX", "%-lX", "%+lX", "% lX", "%#lX", "%0lX", "%-+ #0lX", "%9lX", "%-9lX", "%+9lX", "% 9lX", "%#9lX", "%09lX", "%-+ #09lX", "%.9lX", "%-.9lX", "%+.9lX", "% .9lX", "%#.9lX", "%0.9lX", "%-+ #0.9lX", "%9.lX", "%-9.lX", "%+9.lX", "% 9.lX", "%#9.lX", "%09.lX", "%-+ #09.lX", "%9.9lX", "%-9.9lX", "%+9.9lX", "% 9.9lX", "%#9.9lX", "%09.9lX", "%-+ #09.9lX", "%.0lX", "%-.0lX", "%+.0lX", "% .0lX", "%#.0lX", "%0.0lX", "%-+ #0.0lX", "%.1lX", "%-.1lX", "%+.1lX", "% .1lX", "%#.1lX", "%0.1lX", "%-+ #0.1lX", "%.10000lX", "%-.10000lX", "%+.10000lX", "% .10000lX", "%#.10000lX", "%0.10000lX", "%-+ #0.10000lX", "%10000lX", "%-10000lX", "%+10000lX", "% 10000lX", "%#10000lX", "%010000lX", "%-+ #010000lX", "%10000.10000lX", "%-10000.10000lX", "%+10000.10000lX", "% 10000.10000lX", "%#10000.10000lX", "%010000.10000lX", "%-+ #010000.10000lX", "%-1.5lo", "%1.5lo", "%123.9lo", "%5.5lo", "%10.5lo", "% 10.5lo", "%+22.33lo", "%01.3lo", "%4lo", "%-1.5lu", "%1.5lu", "%123.9lu", "%5.5lu", "%10.5lu", "% 10.5lu", "%+22.33lu", "%01.3lu", "%4lu", "%-1.5lx", "%1.5lx", "%123.9lx", "%5.5lx", "%10.5lx", "% 10.5lx", "%+22.33lx", "%01.3lx", "%4lx", "%-1.5lX", "%1.5lX", "%123.9lX", "%5.5lX", "%10.5lX", "% 10.5lX", "%+22.33lX", "%01.3lX", "%4lX", NULL }; char *luint_fmt2[] = { "%*lo", "%-*lo", "%+*lo", "% *lo", "%#*lo", "%0*lo", "%-+ #0*lo", "%*lu", "%-*lu", "%+*lu", "% *lu", "%#*lu", "%0*lu", "%-+ #0*lu", "%*lx", "%-*lx", "%+*lx", "% *lx", "%#*lx", "%0*lx", "%-+ #0*lx", "%*lX", "%-*lX", "%+*lX", "% *lX", "%#*lX", "%0*lX", "%-+ #0*lX", NULL }; char *luint_fmt3[] = { "%.*lo", "%-.*lo", "%+.*lo", "% .*lo", "%#.*lo", "%0.*lo", "%-+ #0.*lo", "%.*lu", "%-.*lu", "%+.*lu", "% .*lu", "%#.*lu", "%0.*lu", "%-+ #0.*lu", "%.*lx", "%-.*lx", "%+.*lx", "% .*lx", "%#.*lx", "%0.*lx", "%-+ #0.*lx", "%.*lX", "%-.*lX", "%+.*lX", "% .*lX", "%#.*lX", "%0.*lX", "%-+ #0.*lX", NULL }; char *luint_fmt4[] = { "%*.*lo", "%-*.*lo", "%+*.*lo", "% *.*lo", "%#*.*lo", "%0*.*lo", "%-+ #0*.*lo", "%*.*lu", "%-*.*lu", "%+*.*lu", "% *.*lu", "%#*.*lu", "%0*.*lu", "%-+ #0*.*lu", "%*.*lx", "%-*.*lx", "%+*.*lx", "% *.*lx", "%#*.*lx", "%0*.*lx", "%-+ #0*.*lx", "%*.*lX", "%-*.*lX", "%+*.*lX", "% *.*lX", "%#*.*lX", "%0*.*lX", "%-+ #0*.*lX", NULL }; unsigned long uint_nums[] = { 0xffffffff, 134, 91340, 341, 0203, 0, 0xffff3333 }; char *str_fmt[] = { "%s", "%-s", "%9s", "%-9s", "%.9s", "%-.9s", "%9.s", "%-9.s", "%9.9s", "%-9.9s", "%.0s", "%-.0s", "%.1s", "%-.1s", "%.10000s", "%-.10000s", "%10000s", "%-10000s", "%10000.10000s", "%-10000.10000s", NULL }; char *str_fmt2[] = { "%*s", "%-*s", NULL }; char *str_fmt3[] = { "%.*s", "%-.*s", NULL }; char *str_fmt4[] = { "%*.*s", "%-*.*s", NULL }; char *str_vals[] = { #ifdef HAVE_PRINTF_STR_FMT_NULL NULL, #endif "", "a", "ab", "abc", "abcdefgh", "abcdefghi", "abcdefghij", "abcdefghijk", "abcdef\000ghijk" }; char *char_fmt[] = { "%c", "%-c", "%1c", "%-1c", "%2c", "%-2c", "%3c", "%-3c", "%4c", "%-4c", NULL }; char *char_fmt2[] = { "%*c", "%-*c", NULL }; char *char_fmt3[] = { "%.*c", "%-.*c", NULL }; char *char_fmt4[] = { "%*.*c", "%-*.*c", NULL }; char char_vals[] = { 'a', '\0', '\377' }; int widths[] = { 0, 0, 15, 15, 1, 0, 80, 80, 0, -15, -15, -80 }; int precisions[] = { 0, 15, 0, 15, 1, 80, 0, 80, -15, 0, -15, -80 }; /* ** Note: Some of the following may mean something on your system so we don't ** compare this snprintf() with the system's sprintf(). We just check that ** snprintf() returns -1 for these formats. */ char *err_fmt[] = { "%h%", "%l%", "%L%", "%9%", "%.9%", "%9.9%", "%-%", "%+%", "% %", "%#%", "%0%", "%a", "%A", "%b", "%B", "%C", "%D", "%F", "%h", "%H", "%I", "%j", "%J", "%k", "%K", "%l", "%L", "%m", "%M", "%N", "%O", "%P", "%q", "%Q", "%r", "%R", "%S", "%t", "%T", "%U", "%v", "%V", "%w", "%W", "%y", "%Y", "%z", "%Z", NULL }; int main(int ac, char **av) { char buf1[LONG_STRING]; char buf2[LONG_STRING]; int verbose = 0; int x, y, z; int tests = 0; int errors = 0; int len1; int len2; int rc; short hn; int n; long ln; if (ac == 2 && !strcmp(av[1], "help")) { printf("usage: %s [verbose]\n", *av); return EXIT_SUCCESS; } if (ac == 2 && !strcmp(av[1], "verbose")) verbose = 1; printf("Testing: snprintf\n"); #define TEST_SNPRINTF1(fmt, val, vfmt) \ { \ char valstr[1024]; \ sprintf(valstr, (vfmt), (val)); \ ++tests; \ len1 = snprintf(buf1, sizeof(buf1), (fmt), (val)); \ len2 = sprintf(buf2, (fmt), (val)); \ if (len1 != len2) \ ++errors, printf("Test%d: snprintf(%s, %s) failed " \ "(%s, not %s)\n", tests, (fmt), valstr, \ buf1, buf2); \ else if (memcmp(buf1, buf2, len1 + 1)) \ ++errors, printf("Test%d: snprintf(%s, %s) failed " \ "(%s, not %s)\n", tests, (fmt), valstr, \ buf1, buf2); \ else if (verbose) \ printf("Test%d: snprintf(%s, %s) succeeded (%s)\n", tests, \ (fmt), valstr, buf1); \ } #define TEST_SNPRINTF2(fmt, width, precision, val, vfmt) \ { \ char valstr[1024]; \ sprintf(valstr, (vfmt), (val)); \ ++tests; \ len1 = snprintf(buf1, sizeof(buf1), (fmt), (width), (precision), \ (val)); \ len2 = sprintf(buf2, (fmt), (width), (precision), (val)); \ if (len1 != len2) \ ++errors, printf("Test%d: snprintf(%s, %d, %d, %s) failed " \ "(%s, not %s)\n", tests, (fmt), (width), \ (precision), valstr, buf1, buf2); \ else if (memcmp(buf1, buf2, len1 + 1)) \ ++errors, printf("Test%d: snprintf(%s, %d, %d, %s) failed " \ "(%s, not %s)\n", tests, (fmt), (width), \ (precision), valstr, buf1, buf2); \ else if (verbose) \ printf("Test%d: snprintf(%s, %d, %d, %s) succeeded (%s)\n", \ tests, (fmt), (width), (precision), valstr, buf1); \ } #define TEST_SNPRINTF3(fmt, arg, val, vfmt) \ { \ char valstr[1024]; \ sprintf(valstr, (vfmt), (val)); \ ++tests; \ len1 = snprintf(buf1, sizeof(buf1), (fmt), (arg), (val)); \ len2 = sprintf(buf2, (fmt), (arg), (val)); \ if (len1 != len2) \ ++errors, printf("Test%d: snprintf(%s, %d, %s) failed " \ "(%s, not %s)\n", tests, (fmt), (arg), \ valstr, buf1, buf2); \ else if (memcmp(buf1, buf2, len1 + 1)) \ ++errors, printf("Test%d: snprintf(%s, %d, %s) failed " \ "(%s, not %s)\n", tests, (fmt), (arg), \ valstr, buf1, buf2); \ else if (verbose) \ printf("Test%d: snprintf(%s, %d, %s) succeeded (%s)\n", \ tests, (fmt), (arg), valstr, buf1); \ } /* Test int */ for (x = 0; int_fmt[x]; ++x) for (y = 0; y < sizeof(int_nums) / sizeof(*int_nums); ++y) TEST_SNPRINTF1(int_fmt[x], (int)int_nums[y], "%d"); for (x = 0; int_fmt2[x]; ++x) for (y = 0; y < sizeof(int_nums) / sizeof(*int_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF3(int_fmt2[x], widths[z], (int)int_nums[y], "%d"); for (x = 0; int_fmt3[x]; ++x) for (y = 0; y < sizeof(int_nums) / sizeof(*int_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF3(int_fmt3[x], precisions[z], (int)int_nums[y], "%d"); for (x = 0; int_fmt4[x]; ++x) for (y = 0; y < sizeof(int_nums) / sizeof(*int_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF2(int_fmt4[x], widths[z], precisions[z], (int)int_nums[y], "%d"); /* Test short int */ for (x = 0; hint_fmt[x]; ++x) for (y = 0; y < sizeof(int_nums) / sizeof(*int_nums); ++y) TEST_SNPRINTF1(hint_fmt[x], (short)int_nums[y], "%hd"); for (x = 0; hint_fmt2[x]; ++x) for (y = 0; y < sizeof(int_nums) / sizeof(*int_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF3(hint_fmt2[x], widths[z], (short)int_nums[y], "%hd"); for (x = 0; hint_fmt3[x]; ++x) for (y = 0; y < sizeof(int_nums) / sizeof(*int_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF3(hint_fmt3[x], precisions[z], (short)int_nums[y], "%hd"); for (x = 0; hint_fmt4[x]; ++x) for (y = 0; y < sizeof(int_nums) / sizeof(*int_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF2(hint_fmt4[x], widths[z], precisions[z], (short)int_nums[y], "%hd"); /* Test long int */ for (x = 0; lint_fmt[x]; ++x) for (y = 0; y < sizeof(int_nums) / sizeof(*int_nums); ++y) TEST_SNPRINTF1(lint_fmt[x], int_nums[y], "%ld"); for (x = 0; lint_fmt2[x]; ++x) for (y = 0; y < sizeof(int_nums) / sizeof(*int_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF3(lint_fmt2[x], widths[z], int_nums[y], "%ld"); for (x = 0; lint_fmt3[x]; ++x) for (y = 0; y < sizeof(int_nums) / sizeof(*int_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF3(lint_fmt3[x], precisions[z], int_nums[y], "%ld"); for (x = 0; lint_fmt4[x]; ++x) for (y = 0; y < sizeof(int_nums) / sizeof(*int_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF2(lint_fmt4[x], widths[z], precisions[z], int_nums[y], "%ld"); /* Test unsigned int */ for (x = 0; uint_fmt[x]; ++x) for (y = 0; y < sizeof(uint_nums) / sizeof(*uint_nums); ++y) TEST_SNPRINTF1(uint_fmt[x], (unsigned int)uint_nums[y], "%u"); for (x = 0; uint_fmt2[x]; ++x) for (y = 0; y < sizeof(uint_nums) / sizeof(*uint_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF3(uint_fmt2[x], widths[z], (unsigned int)uint_nums[y], "%u"); for (x = 0; uint_fmt3[x]; ++x) for (y = 0; y < sizeof(uint_nums) / sizeof(*uint_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF3(uint_fmt3[x], precisions[z], (unsigned int)uint_nums[y], "%u"); for (x = 0; uint_fmt4[x]; ++x) for (y = 0; y < sizeof(uint_nums) / sizeof(*uint_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF2(uint_fmt4[x], widths[z], precisions[z], (unsigned int)uint_nums[y], "%u"); /* Test unsigned short int */ for (x = 0; huint_fmt[x]; ++x) for (y = 0; y < sizeof(uint_nums) / sizeof(*uint_nums); ++y) TEST_SNPRINTF1(huint_fmt[x], (unsigned short)uint_nums[y], "%hu"); for (x = 0; huint_fmt2[x]; ++x) for (y = 0; y < sizeof(uint_nums) / sizeof(*uint_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF3(huint_fmt2[x], widths[z], (unsigned short)uint_nums[y], "%hu"); for (x = 0; huint_fmt3[x]; ++x) for (y = 0; y < sizeof(uint_nums) / sizeof(*uint_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF3(huint_fmt3[x], precisions[z], (unsigned short)uint_nums[y], "%hu"); for (x = 0; huint_fmt4[x]; ++x) for (y = 0; y < sizeof(uint_nums) / sizeof(*uint_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF2(huint_fmt4[x], widths[z], precisions[z], (unsigned short)uint_nums[y], "%hu"); /* Test unsigned long int */ for (x = 0; luint_fmt[x]; ++x) for (y = 0; y < sizeof(uint_nums) / sizeof(*uint_nums); ++y) TEST_SNPRINTF1(luint_fmt[x], (unsigned long)uint_nums[y], "%lu"); for (x = 0; luint_fmt2[x]; ++x) for (y = 0; y < sizeof(uint_nums) / sizeof(*uint_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF3(luint_fmt2[x], widths[z], (unsigned long)uint_nums[y], "%lu"); for (x = 0; luint_fmt3[x]; ++x) for (y = 0; y < sizeof(uint_nums) / sizeof(*uint_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF3(luint_fmt3[x], precisions[z], (unsigned long)uint_nums[y], "%lu"); for (x = 0; luint_fmt4[x]; ++x) for (y = 0; y < sizeof(uint_nums) / sizeof(*uint_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF2(luint_fmt4[x], widths[z], precisions[z], (unsigned long)uint_nums[y], "%lu"); /* Test double */ for (x = 0; fp_fmt[x]; ++x) for (y = 0; y < sizeof(fp_nums) / sizeof(*fp_nums); ++y) TEST_SNPRINTF1(fp_fmt[x], (double)fp_nums[y], "%g"); for (x = 0; fp_fmt2[x]; ++x) for (y = 0; y < sizeof(fp_nums) / sizeof(*fp_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF3(fp_fmt2[x], widths[z], (double)fp_nums[y], "%g"); for (x = 0; fp_fmt3[x]; ++x) for (y = 0; y < sizeof(fp_nums) / sizeof(*fp_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF3(fp_fmt3[x], precisions[z], (double)fp_nums[y], "%g"); for (x = 0; fp_fmt4[x]; ++x) for (y = 0; y < sizeof(fp_nums) / sizeof(*fp_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF2(fp_fmt4[x], widths[z], precisions[z], (double)fp_nums[y], "%g"); /* Test long double */ for (x = 0; fp_ldbl_fmt[x]; ++x) for (y = 0; y < sizeof(fp_nums) / sizeof(*fp_nums); ++y) TEST_SNPRINTF1(fp_ldbl_fmt[x], fp_nums[y], "%Lg"); for (x = 0; fp_ldbl_fmt2[x]; ++x) for (y = 0; y < sizeof(fp_nums) / sizeof(*fp_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF3(fp_ldbl_fmt2[x], widths[z], fp_nums[y], "%Lg"); for (x = 0; fp_ldbl_fmt3[x]; ++x) for (y = 0; y < sizeof(fp_nums) / sizeof(*fp_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF3(fp_ldbl_fmt3[x], precisions[z], fp_nums[y], "%Lg"); for (x = 0; fp_ldbl_fmt4[x]; ++x) for (y = 0; y < sizeof(fp_nums) / sizeof(*fp_nums); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF2(fp_ldbl_fmt4[x], widths[z], precisions[z], fp_nums[y], "%Lg"); /* Test strings */ for (x = 0; str_fmt[x]; ++x) for (y = 0; y < sizeof(str_vals) / sizeof(*str_vals); ++y) TEST_SNPRINTF1(str_fmt[x], str_vals[y], "%s"); for (x = 0; str_fmt2[x]; ++x) for (y = 0; y < sizeof(str_vals) / sizeof(*str_vals); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF3(str_fmt2[x], widths[z], str_vals[y], "%s"); for (x = 0; str_fmt3[x]; ++x) for (y = 0; y < sizeof(str_vals) / sizeof(*str_vals); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF3(str_fmt3[x], precisions[z], str_vals[y], "%s"); for (x = 0; str_fmt4[x]; ++x) for (y = 0; y < sizeof(str_vals) / sizeof(*str_vals); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF2(str_fmt4[x], widths[z], precisions[z], str_vals[y], "%s"); /* Test characters */ for (x = 0; char_fmt[x]; ++x) for (y = 0; y < sizeof(char_vals) / sizeof(*char_vals); ++y) TEST_SNPRINTF1(char_fmt[x], char_vals[y], "%c"); for (x = 0; char_fmt2[x]; ++x) for (y = 0; y < sizeof(char_vals) / sizeof(*char_vals); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF3(char_fmt2[x], widths[z], char_vals[y], "%c"); for (x = 0; char_fmt3[x]; ++x) for (y = 0; y < sizeof(char_vals) / sizeof(*char_vals); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF3(char_fmt3[x], precisions[z], char_vals[y], "%c"); for (x = 0; char_fmt4[x]; ++x) for (y = 0; y < sizeof(char_vals) / sizeof(*char_vals); ++y) for (z = 0; z < sizeof(widths) / sizeof(*widths); ++z) TEST_SNPRINTF2(char_fmt4[x], widths[z], precisions[z], char_vals[y], "%c"); /* Test %[n%] */ #define TEST_SNPRINTF4(action, eq, buf, val, size, n, nval) \ if (++tests, (rc = (action)) != (eq)) \ ++errors, printf("Test%d: %s failed (returned %d, not %d)\n", \ tests, (#action), rc, (eq)); \ else if ((n) != (nval)) \ ++errors, printf("Test%d: %s failed (output %ld, not %ld)\n", \ tests, (#action), (long)(n), (long)(nval)); \ else if (buf && val && (size) && memcmp((buf), (val), (size))) \ ++errors, printf("Test%d: %s failed (%s, not %s)\n", tests, \ (#action), (char *)(buf), (char *)(val)); \ else if (verbose) \ printf("Test%d: %s succeeded (%s = %ld)\n", tests, (#action), \ (#n), (long)n); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "%n", &n), 0, buf1, "", 1, n, 0); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "%n1", &n), 1, buf1, "1", 2, n, 0); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "a%n", &n), 1, buf1, "a", 2, n, 1); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "a%nb", &n), 2, buf1, "ab", 3, n, 1); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "ab%n", &n), 2, buf1, "ab", 3, n, 2); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "ab%nc", &n), 3, buf1, "abc", 4, n, 2); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "abc%n", &n), 3, buf1, "abc", 4, n, 3); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "abc%ndef", &n), 6, buf1, "abcdef", 7, n, 3); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "%d %d %d%n %d", 1, 1, 1, &n, 1), 7, buf1, "1 1 1 1", 8, n, 5); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "%g%n", 1.5, &n), 3, buf1, "1.5", 4, n, 3); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "%g%n1", 1.5, &n), 4, buf1, "1.51", 5, n, 3); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "%s%n", "a string", &n), 8, buf1, "a string", 9, n, 8); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "%s%n1", "a string", &n), 9, buf1, "a string1", 10, n, 8); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "%hn", &hn), 0, buf1, "", 1, hn, 0); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "%hn1", &hn), 1, buf1, "1", 2, hn, 0); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "a%hn", &hn), 1, buf1, "a", 2, hn, 1); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "a%hnb", &hn), 2, buf1, "ab", 3, hn, 1); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "ab%hn", &hn), 2, buf1, "ab", 3, hn, 2); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "ab%hnc", &hn), 3, buf1, "abc", 4, hn, 2); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "abc%hn", &hn), 3, buf1, "abc", 4, hn, 3); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "abc%hndef", &hn), 6, buf1, "abcdef", 7, hn, 3); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "%d %d %d%hn %d", 1, 1, 1, &hn, 1), 7, buf1, "1 1 1 1", 8, hn, 5); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "%g%hn", 1.5, &hn), 3, buf1, "1.5", 4, hn, 3); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "%g%hn1", 1.5, &hn), 4, buf1, "1.51", 5, hn, 3); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "%s%hn", "a string", &hn), 8, buf1, "a string", 9, hn, 8); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "%s%hn1", "a string", &hn), 9, buf1, "a string1", 10, hn, 8); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "%ln", &ln), 0, buf1, "", 1, ln, 0); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "%ln1", &ln), 1, buf1, "1", 2, ln, 0); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "a%ln", &ln), 1, buf1, "a", 2, ln, 1); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "a%lnb", &ln), 2, buf1, "ab", 3, ln, 1); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "ab%ln", &ln), 2, buf1, "ab", 3, ln, 2); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "ab%lnc", &ln), 3, buf1, "abc", 4, ln, 2); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "abc%ln", &ln), 3, buf1, "abc", 4, ln, 3); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "abc%lndef", &ln), 6, buf1, "abcdef", 7, ln, 3); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "%d %d %d%ln %d", 1, 1, 1, &ln, 1), 7, buf1, "1 1 1 1", 8, ln, 5); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "%g%ln", 1.5, &ln), 3, buf1, "1.5", 4, ln, 3); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "%g%ln1", 1.5, &ln), 4, buf1, "1.51", 5, ln, 3); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "%s%ln", "a string", &ln), 8, buf1, "a string", 9, ln, 8); TEST_SNPRINTF4(snprintf(buf1, sizeof(buf1), "%s%ln1", "a string", &ln), 9, buf1, "a string1", 10, ln, 8); TEST_SNPRINTF4(snprintf(NULL, 0, "%n", &n), 0, NULL, NULL, 0, n, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "%n1", &n), 1, NULL, NULL, 0, n, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "a%n", &n), 1, NULL, NULL, 0, n, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "a%nb", &n), 2, NULL, NULL, 0, n, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "ab%n", &n), 2, NULL, NULL, 0, n, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "ab%nc", &n), 3, NULL, NULL, 0, n, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "abc%n", &n), 3, NULL, NULL, 0, n, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "abc%ndef", &n), 6, NULL, NULL, 0, n, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "%d %d %d%n %d", 1, 1, 1, &n, 1), 7, NULL, NULL, 0, n, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "%g%n", 1.5, &n), 3, NULL, NULL, 0, n, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "%g%n1", 1.5, &n), 4, NULL, NULL, 0, n, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "%s%n", "a string", &n), 8, NULL, NULL, 0, n, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "%s%n1", "a string", &n), 9, NULL, NULL, 0, n, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "%hn", &hn), 0, NULL, NULL, 0, hn, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "%hn1", &hn), 1, NULL, NULL, 0, hn, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "a%hn", &hn), 1, NULL, NULL, 0, hn, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "a%hnb", &hn), 2, NULL, NULL, 0, hn, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "ab%hn", &hn), 2, NULL, NULL, 0, hn, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "ab%hnc", &hn), 3, NULL, NULL, 0, hn, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "abc%hn", &hn), 3, NULL, NULL, 0, hn, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "abc%hndef", &hn), 6, NULL, NULL, 0, hn, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "%d %d %d%hn %d", 1, 1, 1, &hn, 1), 7, NULL, NULL, 0, hn, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "%g%hn", 1.5, &hn), 3, NULL, NULL, 0, hn, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "%g%hn1", 1.5, &hn), 4, NULL, NULL, 0, hn, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "%s%hn", "a string", &hn), 8, NULL, NULL, 0, hn, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "%s%hn1", "a string", &hn), 9, NULL, NULL, 0, hn, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "%ln", &ln), 0, NULL, NULL, 0, ln, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "%ln1", &ln), 1, NULL, NULL, 0, ln, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "a%ln", &ln), 1, NULL, NULL, 0, ln, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "a%lnb", &ln), 2, NULL, NULL, 0, ln, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "ab%ln", &ln), 2, NULL, NULL, 0, ln, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "ab%lnc", &ln), 3, NULL, NULL, 0, ln, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "abc%ln", &ln), 3, NULL, NULL, 0, ln, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "abc%lndef", &ln), 6, NULL, NULL, 0, ln, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "%d %d %d%ln %d", 1, 1, 1, &ln, 1), 7, NULL, NULL, 0, ln, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "%g%ln", 1.5, &ln), 3, NULL, NULL, 0, ln, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "%g%ln1", 1.5, &ln), 4, NULL, NULL, 0, ln, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "%s%ln", "a string", &ln), 8, NULL, NULL, 0, ln, 0); TEST_SNPRINTF4(snprintf(NULL, 0, "%s%ln1", "a string", &ln), 9, NULL, NULL, 0, ln, 0); /* Test truncation and return value */ #define TEST_SNPRINTF5(action, eq, buf, val, size) \ if (++tests, (rc = (action)) != (eq)) \ ++errors, printf("Test%d: %s failed (returned %d, not %d)\n", \ tests, (#action), rc, (eq)); \ else if (buf && val && (size) && memcmp((buf), (val), (size))) \ ++errors, printf("Test%d: %s failed (%s, not %s)\n", tests, \ (#action), (char *)(buf), (char *)(val)); TEST_SNPRINTF5(snprintf(NULL, 0, ""), 0, NULL, NULL, 0); TEST_SNPRINTF5(snprintf(NULL, 0, "abc"), 3, NULL, NULL, 0); TEST_SNPRINTF5(snprintf(buf1, 1, "abc"), 3, buf1, "", 1); TEST_SNPRINTF5(snprintf(buf1, 1, "%s", "abc"), 3, buf1, "", 1); TEST_SNPRINTF5(snprintf(buf1, 1, "%d", 10), 2, buf1, "", 1); TEST_SNPRINTF5(snprintf(buf1, 1, "%i", 10), 2, buf1, "", 1); TEST_SNPRINTF5(snprintf(buf1, 1, "%o", 10), 2, buf1, "", 1); TEST_SNPRINTF5(snprintf(buf1, 1, "%u", 10), 2, buf1, "", 1); TEST_SNPRINTF5(snprintf(buf1, 1, "%x", 10), 1, buf1, "", 1); TEST_SNPRINTF5(snprintf(buf1, 1, "%x", 16), 2, buf1, "", 1); TEST_SNPRINTF5(snprintf(buf1, 1, "%X", 16), 2, buf1, "", 1); TEST_SNPRINTF5(snprintf(buf1, 2, "%d", 16), 2, buf1, "1", 2); TEST_SNPRINTF5(snprintf(buf1, 2, "%.1f", -1.5), 4, buf1, "-", 2); TEST_SNPRINTF5(snprintf(buf1, 2, "%.1e", -1.5), 8, buf1, "-", 2); TEST_SNPRINTF5(snprintf(buf1, 2, "%.1E", -1.5), 8, buf1, "-", 2); TEST_SNPRINTF5(snprintf(buf1, 2, "%.2g", -1.5), 4, buf1, "-", 2); ;TEST_SNPRINTF5(snprintf(buf1, 2, "%.2G", -1.5), 4, buf1, "-", 2); TEST_SNPRINTF5(snprintf(buf1, 3, "%s", "abcd"), 4, buf1, "ab", 3); /* Test error reporting */ #define TEST_SNPRINTF6(action, fmt) \ if (++tests, (rc = (action)) != -1) \ ++errors, printf("Test%d: snprintf(NULL, 0, \"%s\") failed " \ "(returned %d, not %d)\n", tests, (fmt), rc, \ -1); \ else if (verbose) \ printf("Test%d: snprintf(NULL, 0, \"%s\") succeeded " \ "(returned -1)\n", tests, (fmt)); for (x = 0; err_fmt[x]; ++x) TEST_SNPRINTF6(snprintf(NULL, 0, err_fmt[x]), err_fmt[x]); if (errors) printf("%d/%d tests failed\n", errors, tests); else printf("All tests passed\n"); if (errors) { printf("\n"); printf(" Note: You can ignore any errors involving %%p or NULL " "pointers (%%p or %%s).\n"); printf(" They are undefined by the ISO C standard so any " "behaviour is correct.\n"); printf("\n"); printf(" Note: There are some tests for combinations of flags " "and conversions that\n"); printf(" are undefined by the ISO C standard so any behaviour " "is correct.\n"); printf(" This implementation can be configured to behave like " "Linux or Solaris.\n"); printf(" On other systems, these tests may fail.\n"); printf("\n"); printf(" Note: There may also be failures that indicate that " "this system's sprintf()\n"); printf(" is not ISO C compliant since most of the tests just " "compare the output of\n"); printf(" snprintf() with this system's sprintf().\n"); } return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } #endif