12b15cb3dSCy Schubert /* 22b15cb3dSCy Schubert * Modified by Dave Hart for integration into NTP 4.2.7 <hart@ntp.org> 32b15cb3dSCy Schubert * 42b15cb3dSCy Schubert * Changed in a backwards-incompatible way to separate HAVE_SNPRINTF 52b15cb3dSCy Schubert * from HW_WANT_RPL_SNPRINTF, etc. for each of the four replaced 62b15cb3dSCy Schubert * functions. 72b15cb3dSCy Schubert * 82b15cb3dSCy Schubert * Changed to honor hw_force_rpl_snprintf=yes, etc. This is used by NTP 92b15cb3dSCy Schubert * to test rpl_snprintf() and rpl_vsnprintf() on platforms which provide 102b15cb3dSCy Schubert * C99-compliant implementations. 112b15cb3dSCy Schubert */ 122b15cb3dSCy Schubert 132b15cb3dSCy Schubert /* $Id: snprintf.c,v 1.9 2008/01/20 14:02:00 holger Exp $ */ 142b15cb3dSCy Schubert 152b15cb3dSCy Schubert /* 162b15cb3dSCy Schubert * Copyright (c) 1995 Patrick Powell. 172b15cb3dSCy Schubert * 182b15cb3dSCy Schubert * This code is based on code written by Patrick Powell <papowell@astart.com>. 192b15cb3dSCy Schubert * It may be used for any purpose as long as this notice remains intact on all 202b15cb3dSCy Schubert * source code distributions. 212b15cb3dSCy Schubert */ 222b15cb3dSCy Schubert 232b15cb3dSCy Schubert /* 242b15cb3dSCy Schubert * Copyright (c) 2008 Holger Weiss. 252b15cb3dSCy Schubert * 262b15cb3dSCy Schubert * This version of the code is maintained by Holger Weiss <holger@jhweiss.de>. 272b15cb3dSCy Schubert * My changes to the code may freely be used, modified and/or redistributed for 282b15cb3dSCy Schubert * any purpose. It would be nice if additions and fixes to this file (including 292b15cb3dSCy Schubert * trivial code cleanups) would be sent back in order to let me include them in 302b15cb3dSCy Schubert * the version available at <http://www.jhweiss.de/software/snprintf.html>. 312b15cb3dSCy Schubert * However, this is not a requirement for using or redistributing (possibly 322b15cb3dSCy Schubert * modified) versions of this file, nor is leaving this notice intact mandatory. 332b15cb3dSCy Schubert */ 342b15cb3dSCy Schubert 352b15cb3dSCy Schubert /* 362b15cb3dSCy Schubert * History 372b15cb3dSCy Schubert * 382b15cb3dSCy Schubert * 2008-01-20 Holger Weiss <holger@jhweiss.de> for C99-snprintf 1.1: 392b15cb3dSCy Schubert * 402b15cb3dSCy Schubert * Fixed the detection of infinite floating point values on IRIX (and 412b15cb3dSCy Schubert * possibly other systems) and applied another few minor cleanups. 422b15cb3dSCy Schubert * 432b15cb3dSCy Schubert * 2008-01-06 Holger Weiss <holger@jhweiss.de> for C99-snprintf 1.0: 442b15cb3dSCy Schubert * 452b15cb3dSCy Schubert * Added a lot of new features, fixed many bugs, and incorporated various 462b15cb3dSCy Schubert * improvements done by Andrew Tridgell <tridge@samba.org>, Russ Allbery 472b15cb3dSCy Schubert * <rra@stanford.edu>, Hrvoje Niksic <hniksic@xemacs.org>, Damien Miller 482b15cb3dSCy Schubert * <djm@mindrot.org>, and others for the Samba, INN, Wget, and OpenSSH 492b15cb3dSCy Schubert * projects. The additions include: support the "e", "E", "g", "G", and 502b15cb3dSCy Schubert * "F" conversion specifiers (and use conversion style "f" or "F" for the 512b15cb3dSCy Schubert * still unsupported "a" and "A" specifiers); support the "hh", "ll", "j", 522b15cb3dSCy Schubert * "t", and "z" length modifiers; support the "#" flag and the (non-C99) 532b15cb3dSCy Schubert * "'" flag; use localeconv(3) (if available) to get both the current 542b15cb3dSCy Schubert * locale's decimal point character and the separator between groups of 552b15cb3dSCy Schubert * digits; fix the handling of various corner cases of field width and 562b15cb3dSCy Schubert * precision specifications; fix various floating point conversion bugs; 572b15cb3dSCy Schubert * handle infinite and NaN floating point values; don't attempt to write to 582b15cb3dSCy Schubert * the output buffer (which may be NULL) if a size of zero was specified; 592b15cb3dSCy Schubert * check for integer overflow of the field width, precision, and return 602b15cb3dSCy Schubert * values and during the floating point conversion; use the OUTCHAR() macro 612b15cb3dSCy Schubert * instead of a function for better performance; provide asprintf(3) and 622b15cb3dSCy Schubert * vasprintf(3) functions; add new test cases. The replacement functions 632b15cb3dSCy Schubert * have been renamed to use an "rpl_" prefix, the function calls in the 642b15cb3dSCy Schubert * main project (and in this file) must be redefined accordingly for each 652b15cb3dSCy Schubert * replacement function which is needed (by using Autoconf or other means). 662b15cb3dSCy Schubert * Various other minor improvements have been applied and the coding style 672b15cb3dSCy Schubert * was cleaned up for consistency. 682b15cb3dSCy Schubert * 692b15cb3dSCy Schubert * 2007-07-23 Holger Weiss <holger@jhweiss.de> for Mutt 1.5.13: 702b15cb3dSCy Schubert * 712b15cb3dSCy Schubert * C99 compliant snprintf(3) and vsnprintf(3) functions return the number 722b15cb3dSCy Schubert * of characters that would have been written to a sufficiently sized 732b15cb3dSCy Schubert * buffer (excluding the '\0'). The original code simply returned the 742b15cb3dSCy Schubert * length of the resulting output string, so that's been fixed. 752b15cb3dSCy Schubert * 762b15cb3dSCy Schubert * 1998-03-05 Michael Elkins <me@mutt.org> for Mutt 0.90.8: 772b15cb3dSCy Schubert * 782b15cb3dSCy Schubert * The original code assumed that both snprintf(3) and vsnprintf(3) were 792b15cb3dSCy Schubert * missing. Some systems only have snprintf(3) but not vsnprintf(3), so 802b15cb3dSCy Schubert * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. 812b15cb3dSCy Schubert * 822b15cb3dSCy Schubert * 1998-01-27 Thomas Roessler <roessler@does-not-exist.org> for Mutt 0.89i: 832b15cb3dSCy Schubert * 842b15cb3dSCy Schubert * The PGP code was using unsigned hexadecimal formats. Unfortunately, 852b15cb3dSCy Schubert * unsigned formats simply didn't work. 862b15cb3dSCy Schubert * 872b15cb3dSCy Schubert * 1997-10-22 Brandon Long <blong@fiction.net> for Mutt 0.87.1: 882b15cb3dSCy Schubert * 892b15cb3dSCy Schubert * Ok, added some minimal floating point support, which means this probably 902b15cb3dSCy Schubert * requires libm on most operating systems. Don't yet support the exponent 912b15cb3dSCy Schubert * (e,E) and sigfig (g,G). Also, fmtint() was pretty badly broken, it just 922b15cb3dSCy Schubert * wasn't being exercised in ways which showed it, so that's been fixed. 932b15cb3dSCy Schubert * Also, formatted the code to Mutt conventions, and removed dead code left 942b15cb3dSCy Schubert * over from the original. Also, there is now a builtin-test, run with: 952b15cb3dSCy Schubert * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm && ./snprintf 962b15cb3dSCy Schubert * 972b15cb3dSCy Schubert * 2996-09-15 Brandon Long <blong@fiction.net> for Mutt 0.43: 982b15cb3dSCy Schubert * 992b15cb3dSCy Schubert * This was ugly. It is still ugly. I opted out of floating point 1002b15cb3dSCy Schubert * numbers, but the formatter understands just about everything from the 1012b15cb3dSCy Schubert * normal C string format, at least as far as I can tell from the Solaris 1022b15cb3dSCy Schubert * 2.5 printf(3S) man page. 1032b15cb3dSCy Schubert */ 1042b15cb3dSCy Schubert 1052b15cb3dSCy Schubert /* 1062b15cb3dSCy Schubert * ToDo 1072b15cb3dSCy Schubert * 1082b15cb3dSCy Schubert * - Add wide character support. 1092b15cb3dSCy Schubert * - Add support for "%a" and "%A" conversions. 1102b15cb3dSCy Schubert * - Create test routines which predefine the expected results. Our test cases 1112b15cb3dSCy Schubert * usually expose bugs in system implementations rather than in ours :-) 1122b15cb3dSCy Schubert */ 1132b15cb3dSCy Schubert 1142b15cb3dSCy Schubert /* 1152b15cb3dSCy Schubert * Usage 1162b15cb3dSCy Schubert * 1172b15cb3dSCy Schubert * 1) The following preprocessor macros should be defined to 1 if the feature or 1182b15cb3dSCy Schubert * file in question is available on the target system (by using Autoconf or 1192b15cb3dSCy Schubert * other means), though basic functionality should be available as long as 1202b15cb3dSCy Schubert * HAVE_STDARG_H and HAVE_STDLIB_H are defined correctly: 1212b15cb3dSCy Schubert * 1222b15cb3dSCy Schubert * HW_WANT_RPL_VSNPRINTF 1232b15cb3dSCy Schubert * HW_WANT_RPL_SNPRINTF 1242b15cb3dSCy Schubert * HW_WANT_RPL_VASPRINTF 1252b15cb3dSCy Schubert * HW_WANT_RPL_ASPRINTF 1262b15cb3dSCy Schubert * HAVE_VSNPRINTF // define to 1 #if HW_WANT_RPL_VSNPRINTF 1272b15cb3dSCy Schubert * HAVE_SNPRINTF // define to 1 #if HW_WANT_RPL_SNPRINTF 1282b15cb3dSCy Schubert * HAVE_VASPRINTF // define to 1 #if HW_WANT_RPL_VASPRINTF 1292b15cb3dSCy Schubert * HAVE_ASPRINTF // define to 1 #if HW_WANT_RPL_ASPRINTF 1302b15cb3dSCy Schubert * HAVE_STDARG_H 1312b15cb3dSCy Schubert * HAVE_STDDEF_H 1322b15cb3dSCy Schubert * HAVE_STDINT_H 1332b15cb3dSCy Schubert * HAVE_STDLIB_H 1342b15cb3dSCy Schubert * HAVE_INTTYPES_H 1352b15cb3dSCy Schubert * HAVE_LOCALE_H 1362b15cb3dSCy Schubert * HAVE_LOCALECONV 1372b15cb3dSCy Schubert * HAVE_LCONV_DECIMAL_POINT 1382b15cb3dSCy Schubert * HAVE_LCONV_THOUSANDS_SEP 1392b15cb3dSCy Schubert * HAVE_LONG_DOUBLE 1402b15cb3dSCy Schubert * HAVE_LONG_LONG_INT 1412b15cb3dSCy Schubert * HAVE_UNSIGNED_LONG_LONG_INT 1422b15cb3dSCy Schubert * HAVE_INTMAX_T 1432b15cb3dSCy Schubert * HAVE_UINTMAX_T 1442b15cb3dSCy Schubert * HAVE_UINTPTR_T 1452b15cb3dSCy Schubert * HAVE_PTRDIFF_T 1462b15cb3dSCy Schubert * HAVE_VA_COPY 1472b15cb3dSCy Schubert * HAVE___VA_COPY 1482b15cb3dSCy Schubert * 1492b15cb3dSCy Schubert * 2) The calls to the functions which should be replaced must be redefined 1502b15cb3dSCy Schubert * throughout the project files (by using Autoconf or other means): 1512b15cb3dSCy Schubert * 1522b15cb3dSCy Schubert * #if HW_WANT_RPL_VSNPRINTF 1532b15cb3dSCy Schubert * #define vsnprintf rpl_vsnprintf 1542b15cb3dSCy Schubert * #endif 1552b15cb3dSCy Schubert * #if HW_WANT_RPL_SNPRINTF 1562b15cb3dSCy Schubert * #define snprintf rpl_snprintf 1572b15cb3dSCy Schubert * #endif 1582b15cb3dSCy Schubert * #if HW_WANT_RPL_VASPRINTF 1592b15cb3dSCy Schubert * #define vasprintf rpl_vasprintf 1602b15cb3dSCy Schubert * #endif 1612b15cb3dSCy Schubert * #if HW_WANT_RPL_ASPRINTF 1622b15cb3dSCy Schubert * #define asprintf rpl_asprintf 1632b15cb3dSCy Schubert * #endif 1642b15cb3dSCy Schubert * 1652b15cb3dSCy Schubert * 3) The required replacement functions should be declared in some header file 1662b15cb3dSCy Schubert * included throughout the project files: 1672b15cb3dSCy Schubert * 1682b15cb3dSCy Schubert * #if HAVE_CONFIG_H 1692b15cb3dSCy Schubert * #include <config.h> 1702b15cb3dSCy Schubert * #endif 1712b15cb3dSCy Schubert * #if HAVE_STDARG_H 1722b15cb3dSCy Schubert * #include <stdarg.h> 1732b15cb3dSCy Schubert * #if HW_WANT_RPL_VSNPRINTF 1742b15cb3dSCy Schubert * int rpl_vsnprintf(char *, size_t, const char *, va_list); 1752b15cb3dSCy Schubert * #endif 1762b15cb3dSCy Schubert * #if HW_WANT_RPL_SNPRINTF 1772b15cb3dSCy Schubert * int rpl_snprintf(char *, size_t, const char *, ...); 1782b15cb3dSCy Schubert * #endif 1792b15cb3dSCy Schubert * #if HW_WANT_RPL_VASPRINTF 1802b15cb3dSCy Schubert * int rpl_vasprintf(char **, const char *, va_list); 1812b15cb3dSCy Schubert * #endif 1822b15cb3dSCy Schubert * #if HW_WANT_RPL_ASPRINTF 1832b15cb3dSCy Schubert * int rpl_asprintf(char **, const char *, ...); 1842b15cb3dSCy Schubert * #endif 1852b15cb3dSCy Schubert * #endif 1862b15cb3dSCy Schubert * 1872b15cb3dSCy Schubert * Autoconf macros for handling step 1 and step 2 are available at 1882b15cb3dSCy Schubert * <http://www.jhweiss.de/software/snprintf.html>. 1892b15cb3dSCy Schubert */ 1902b15cb3dSCy Schubert 1912b15cb3dSCy Schubert #if HAVE_CONFIG_H 192224ba2bdSOllivier Robert #include <config.h> 1932b15cb3dSCy Schubert #endif /* HAVE_CONFIG_H */ 194224ba2bdSOllivier Robert 1952b15cb3dSCy Schubert #if TEST_SNPRINTF 1962b15cb3dSCy Schubert #include <math.h> /* For pow(3), NAN, and INFINITY. */ 1972b15cb3dSCy Schubert #include <string.h> /* For strcmp(3). */ 1982b15cb3dSCy Schubert #if defined(__NetBSD__) || \ 1992b15cb3dSCy Schubert defined(__FreeBSD__) || \ 2002b15cb3dSCy Schubert defined(__OpenBSD__) || \ 2012b15cb3dSCy Schubert defined(__NeXT__) || \ 2022b15cb3dSCy Schubert defined(__bsd__) 2032b15cb3dSCy Schubert #define OS_BSD 1 2042b15cb3dSCy Schubert #elif defined(sgi) || defined(__sgi) 2052b15cb3dSCy Schubert #ifndef __c99 2062b15cb3dSCy Schubert #define __c99 /* Force C99 mode to get <stdint.h> included on IRIX 6.5.30. */ 2072b15cb3dSCy Schubert #endif /* !defined(__c99) */ 2082b15cb3dSCy Schubert #define OS_IRIX 1 2092b15cb3dSCy Schubert #define OS_SYSV 1 2102b15cb3dSCy Schubert #elif defined(__svr4__) 2112b15cb3dSCy Schubert #define OS_SYSV 1 2122b15cb3dSCy Schubert #elif defined(__linux__) 2132b15cb3dSCy Schubert #define OS_LINUX 1 2142b15cb3dSCy Schubert #endif /* defined(__NetBSD__) || defined(__FreeBSD__) || [...] */ 2152b15cb3dSCy Schubert #if HAVE_CONFIG_H /* Undefine definitions possibly done in config.h. */ 2162b15cb3dSCy Schubert #ifdef HAVE_SNPRINTF 2172b15cb3dSCy Schubert #undef HAVE_SNPRINTF 2182b15cb3dSCy Schubert #endif /* defined(HAVE_SNPRINTF) */ 2192b15cb3dSCy Schubert #ifdef HAVE_VSNPRINTF 2202b15cb3dSCy Schubert #undef HAVE_VSNPRINTF 2212b15cb3dSCy Schubert #endif /* defined(HAVE_VSNPRINTF) */ 2222b15cb3dSCy Schubert #ifdef HAVE_ASPRINTF 2232b15cb3dSCy Schubert #undef HAVE_ASPRINTF 2242b15cb3dSCy Schubert #endif /* defined(HAVE_ASPRINTF) */ 2252b15cb3dSCy Schubert #ifdef HAVE_VASPRINTF 2262b15cb3dSCy Schubert #undef HAVE_VASPRINTF 2272b15cb3dSCy Schubert #endif /* defined(HAVE_VASPRINTF) */ 2282b15cb3dSCy Schubert #ifdef snprintf 2292b15cb3dSCy Schubert #undef snprintf 2302b15cb3dSCy Schubert #endif /* defined(snprintf) */ 2312b15cb3dSCy Schubert #ifdef vsnprintf 2322b15cb3dSCy Schubert #undef vsnprintf 2332b15cb3dSCy Schubert #endif /* defined(vsnprintf) */ 2342b15cb3dSCy Schubert #ifdef asprintf 2352b15cb3dSCy Schubert #undef asprintf 2362b15cb3dSCy Schubert #endif /* defined(asprintf) */ 2372b15cb3dSCy Schubert #ifdef vasprintf 2382b15cb3dSCy Schubert #undef vasprintf 2392b15cb3dSCy Schubert #endif /* defined(vasprintf) */ 2402b15cb3dSCy Schubert #else /* By default, we assume a modern system for testing. */ 2412b15cb3dSCy Schubert #ifndef HAVE_STDARG_H 2422b15cb3dSCy Schubert #define HAVE_STDARG_H 1 2432b15cb3dSCy Schubert #endif /* HAVE_STDARG_H */ 2442b15cb3dSCy Schubert #ifndef HAVE_STDDEF_H 2452b15cb3dSCy Schubert #define HAVE_STDDEF_H 1 2462b15cb3dSCy Schubert #endif /* HAVE_STDDEF_H */ 2472b15cb3dSCy Schubert #ifndef HAVE_STDINT_H 2482b15cb3dSCy Schubert #define HAVE_STDINT_H 1 2492b15cb3dSCy Schubert #endif /* HAVE_STDINT_H */ 2502b15cb3dSCy Schubert #ifndef HAVE_STDLIB_H 2512b15cb3dSCy Schubert #define HAVE_STDLIB_H 1 2522b15cb3dSCy Schubert #endif /* HAVE_STDLIB_H */ 2532b15cb3dSCy Schubert #ifndef HAVE_INTTYPES_H 2542b15cb3dSCy Schubert #define HAVE_INTTYPES_H 1 2552b15cb3dSCy Schubert #endif /* HAVE_INTTYPES_H */ 2562b15cb3dSCy Schubert #ifndef HAVE_LOCALE_H 2572b15cb3dSCy Schubert #define HAVE_LOCALE_H 1 2582b15cb3dSCy Schubert #endif /* HAVE_LOCALE_H */ 2592b15cb3dSCy Schubert #ifndef HAVE_LOCALECONV 2602b15cb3dSCy Schubert #define HAVE_LOCALECONV 1 2612b15cb3dSCy Schubert #endif /* !defined(HAVE_LOCALECONV) */ 2622b15cb3dSCy Schubert #ifndef HAVE_LCONV_DECIMAL_POINT 2632b15cb3dSCy Schubert #define HAVE_LCONV_DECIMAL_POINT 1 2642b15cb3dSCy Schubert #endif /* HAVE_LCONV_DECIMAL_POINT */ 2652b15cb3dSCy Schubert #ifndef HAVE_LCONV_THOUSANDS_SEP 2662b15cb3dSCy Schubert #define HAVE_LCONV_THOUSANDS_SEP 1 2672b15cb3dSCy Schubert #endif /* HAVE_LCONV_THOUSANDS_SEP */ 2682b15cb3dSCy Schubert #ifndef HAVE_LONG_DOUBLE 2692b15cb3dSCy Schubert #define HAVE_LONG_DOUBLE 1 2702b15cb3dSCy Schubert #endif /* !defined(HAVE_LONG_DOUBLE) */ 2712b15cb3dSCy Schubert #ifndef HAVE_LONG_LONG_INT 2722b15cb3dSCy Schubert #define HAVE_LONG_LONG_INT 1 2732b15cb3dSCy Schubert #endif /* !defined(HAVE_LONG_LONG_INT) */ 2742b15cb3dSCy Schubert #ifndef HAVE_UNSIGNED_LONG_LONG_INT 2752b15cb3dSCy Schubert #define HAVE_UNSIGNED_LONG_LONG_INT 1 2762b15cb3dSCy Schubert #endif /* !defined(HAVE_UNSIGNED_LONG_LONG_INT) */ 2772b15cb3dSCy Schubert #ifndef HAVE_INTMAX_T 2782b15cb3dSCy Schubert #define HAVE_INTMAX_T 1 2792b15cb3dSCy Schubert #endif /* !defined(HAVE_INTMAX_T) */ 2802b15cb3dSCy Schubert #ifndef HAVE_UINTMAX_T 2812b15cb3dSCy Schubert #define HAVE_UINTMAX_T 1 2822b15cb3dSCy Schubert #endif /* !defined(HAVE_UINTMAX_T) */ 2832b15cb3dSCy Schubert #ifndef HAVE_UINTPTR_T 2842b15cb3dSCy Schubert #define HAVE_UINTPTR_T 1 2852b15cb3dSCy Schubert #endif /* !defined(HAVE_UINTPTR_T) */ 2862b15cb3dSCy Schubert #ifndef HAVE_PTRDIFF_T 2872b15cb3dSCy Schubert #define HAVE_PTRDIFF_T 1 2882b15cb3dSCy Schubert #endif /* !defined(HAVE_PTRDIFF_T) */ 2892b15cb3dSCy Schubert #ifndef HAVE_VA_COPY 2902b15cb3dSCy Schubert #define HAVE_VA_COPY 1 2912b15cb3dSCy Schubert #endif /* !defined(HAVE_VA_COPY) */ 2922b15cb3dSCy Schubert #ifndef HAVE___VA_COPY 2932b15cb3dSCy Schubert #define HAVE___VA_COPY 1 2942b15cb3dSCy Schubert #endif /* !defined(HAVE___VA_COPY) */ 2952b15cb3dSCy Schubert #endif /* HAVE_CONFIG_H */ 2962b15cb3dSCy Schubert #define snprintf rpl_snprintf 2972b15cb3dSCy Schubert #define vsnprintf rpl_vsnprintf 2982b15cb3dSCy Schubert #define asprintf rpl_asprintf 2992b15cb3dSCy Schubert #define vasprintf rpl_vasprintf 3002b15cb3dSCy Schubert #endif /* TEST_SNPRINTF */ 301224ba2bdSOllivier Robert 3022b15cb3dSCy Schubert #if HW_WANT_RPL_SNPRINTF || HW_WANT_RPL_VSNPRINTF || HW_WANT_RPL_ASPRINTF || HW_WANT_RPL_VASPRINTF 3032b15cb3dSCy Schubert #include <stdio.h> /* For NULL, size_t, vsnprintf(3), and vasprintf(3). */ 3042b15cb3dSCy Schubert #ifdef VA_START 3052b15cb3dSCy Schubert #undef VA_START 3062b15cb3dSCy Schubert #endif /* defined(VA_START) */ 3072b15cb3dSCy Schubert #ifdef VA_SHIFT 3082b15cb3dSCy Schubert #undef VA_SHIFT 3092b15cb3dSCy Schubert #endif /* defined(VA_SHIFT) */ 3102b15cb3dSCy Schubert #if HAVE_STDARG_H 311224ba2bdSOllivier Robert #include <stdarg.h> 3122b15cb3dSCy Schubert #define VA_START(ap, last) va_start(ap, last) 3132b15cb3dSCy Schubert #define VA_SHIFT(ap, value, type) /* No-op for ANSI C. */ 3142b15cb3dSCy Schubert #else /* Assume <varargs.h> is available. */ 315224ba2bdSOllivier Robert #include <varargs.h> 3162b15cb3dSCy Schubert #define VA_START(ap, last) va_start(ap) /* "last" is ignored. */ 3172b15cb3dSCy Schubert #define VA_SHIFT(ap, value, type) value = va_arg(ap, type) 3182b15cb3dSCy Schubert #endif /* HAVE_STDARG_H */ 319224ba2bdSOllivier Robert 3202b15cb3dSCy Schubert #if HW_WANT_RPL_VASPRINTF 3212b15cb3dSCy Schubert #if HAVE_STDLIB_H 3222b15cb3dSCy Schubert #include <stdlib.h> /* For malloc(3). */ 3232b15cb3dSCy Schubert #endif /* HAVE_STDLIB_H */ 3242b15cb3dSCy Schubert #ifdef VA_COPY 3252b15cb3dSCy Schubert #undef VA_COPY 3262b15cb3dSCy Schubert #endif /* defined(VA_COPY) */ 3272b15cb3dSCy Schubert #ifdef VA_END_COPY 3282b15cb3dSCy Schubert #undef VA_END_COPY 3292b15cb3dSCy Schubert #endif /* defined(VA_END_COPY) */ 3302b15cb3dSCy Schubert #if HAVE_VA_COPY 3312b15cb3dSCy Schubert #define VA_COPY(dest, src) va_copy(dest, src) 3322b15cb3dSCy Schubert #define VA_END_COPY(ap) va_end(ap) 3332b15cb3dSCy Schubert #elif HAVE___VA_COPY 3342b15cb3dSCy Schubert #define VA_COPY(dest, src) __va_copy(dest, src) 3352b15cb3dSCy Schubert #define VA_END_COPY(ap) va_end(ap) 3362b15cb3dSCy Schubert #else 3372b15cb3dSCy Schubert #define VA_COPY(dest, src) (void)mymemcpy(&dest, &src, sizeof(va_list)) 3382b15cb3dSCy Schubert #define VA_END_COPY(ap) /* No-op. */ 3392b15cb3dSCy Schubert #define NEED_MYMEMCPY 1 3402b15cb3dSCy Schubert static void *mymemcpy(void *, void *, size_t); 3412b15cb3dSCy Schubert #endif /* HAVE_VA_COPY */ 3422b15cb3dSCy Schubert #endif /* HW_WANT_RPL_VASPRINTF */ 3439c2daa00SOllivier Robert 3442b15cb3dSCy Schubert #if HW_WANT_RPL_VSNPRINTF 3452b15cb3dSCy Schubert #include <errno.h> /* For ERANGE and errno. */ 3462b15cb3dSCy Schubert #include <limits.h> /* For *_MAX. */ 3472b15cb3dSCy Schubert #if HAVE_INTTYPES_H 3482b15cb3dSCy Schubert #include <inttypes.h> /* For intmax_t (if not defined in <stdint.h>). */ 3492b15cb3dSCy Schubert #endif /* HAVE_INTTYPES_H */ 3502b15cb3dSCy Schubert #if HAVE_LOCALE_H 3512b15cb3dSCy Schubert #include <locale.h> /* For localeconv(3). */ 3522b15cb3dSCy Schubert #endif /* HAVE_LOCALE_H */ 3532b15cb3dSCy Schubert #if HAVE_STDDEF_H 3542b15cb3dSCy Schubert #include <stddef.h> /* For ptrdiff_t. */ 3552b15cb3dSCy Schubert #endif /* HAVE_STDDEF_H */ 3562b15cb3dSCy Schubert #if HAVE_STDINT_H 3572b15cb3dSCy Schubert #include <stdint.h> /* For intmax_t. */ 3582b15cb3dSCy Schubert #endif /* HAVE_STDINT_H */ 3592b15cb3dSCy Schubert 3602b15cb3dSCy Schubert /* Support for unsigned long long int. We may also need ULLONG_MAX. */ 3612b15cb3dSCy Schubert #ifndef ULONG_MAX /* We may need ULONG_MAX as a fallback. */ 3622b15cb3dSCy Schubert #ifdef UINT_MAX 3632b15cb3dSCy Schubert #define ULONG_MAX UINT_MAX 364224ba2bdSOllivier Robert #else 3652b15cb3dSCy Schubert #define ULONG_MAX INT_MAX 3662b15cb3dSCy Schubert #endif /* defined(UINT_MAX) */ 3672b15cb3dSCy Schubert #endif /* !defined(ULONG_MAX) */ 3682b15cb3dSCy Schubert #ifdef ULLONG 3692b15cb3dSCy Schubert #undef ULLONG 3702b15cb3dSCy Schubert #endif /* defined(ULLONG) */ 3712b15cb3dSCy Schubert #if HAVE_UNSIGNED_LONG_LONG_INT 3722b15cb3dSCy Schubert #define ULLONG unsigned long long int 3732b15cb3dSCy Schubert #ifndef ULLONG_MAX 3742b15cb3dSCy Schubert #define ULLONG_MAX ULONG_MAX 3752b15cb3dSCy Schubert #endif /* !defined(ULLONG_MAX) */ 376224ba2bdSOllivier Robert #else 3772b15cb3dSCy Schubert #define ULLONG unsigned long int 3782b15cb3dSCy Schubert #ifdef ULLONG_MAX 3792b15cb3dSCy Schubert #undef ULLONG_MAX 3802b15cb3dSCy Schubert #endif /* defined(ULLONG_MAX) */ 3812b15cb3dSCy Schubert #define ULLONG_MAX ULONG_MAX 3822b15cb3dSCy Schubert #endif /* HAVE_LONG_LONG_INT */ 3832b15cb3dSCy Schubert 3842b15cb3dSCy Schubert /* Support for uintmax_t. We also need UINTMAX_MAX. */ 3852b15cb3dSCy Schubert #ifdef UINTMAX_T 3862b15cb3dSCy Schubert #undef UINTMAX_T 3872b15cb3dSCy Schubert #endif /* defined(UINTMAX_T) */ 3882b15cb3dSCy Schubert #if HAVE_UINTMAX_T || defined(uintmax_t) 3892b15cb3dSCy Schubert #define UINTMAX_T uintmax_t 3902b15cb3dSCy Schubert #ifndef UINTMAX_MAX 3912b15cb3dSCy Schubert #define UINTMAX_MAX ULLONG_MAX 3922b15cb3dSCy Schubert #endif /* !defined(UINTMAX_MAX) */ 393224ba2bdSOllivier Robert #else 3942b15cb3dSCy Schubert #define UINTMAX_T ULLONG 3952b15cb3dSCy Schubert #ifdef UINTMAX_MAX 3962b15cb3dSCy Schubert #undef UINTMAX_MAX 3972b15cb3dSCy Schubert #endif /* defined(UINTMAX_MAX) */ 3982b15cb3dSCy Schubert #define UINTMAX_MAX ULLONG_MAX 3992b15cb3dSCy Schubert #endif /* HAVE_UINTMAX_T || defined(uintmax_t) */ 4002b15cb3dSCy Schubert 4012b15cb3dSCy Schubert /* Support for long double. */ 4022b15cb3dSCy Schubert #ifndef LDOUBLE 4032b15cb3dSCy Schubert #if HAVE_LONG_DOUBLE 4042b15cb3dSCy Schubert #define LDOUBLE long double 4052b15cb3dSCy Schubert #else 4062b15cb3dSCy Schubert #define LDOUBLE double 4072b15cb3dSCy Schubert #endif /* HAVE_LONG_DOUBLE */ 4082b15cb3dSCy Schubert #endif /* !defined(LDOUBLE) */ 4092b15cb3dSCy Schubert 4102b15cb3dSCy Schubert /* Support for long long int. */ 4112b15cb3dSCy Schubert #ifndef LLONG 4122b15cb3dSCy Schubert #if HAVE_LONG_LONG_INT 4132b15cb3dSCy Schubert #define LLONG long long int 4142b15cb3dSCy Schubert #else 4152b15cb3dSCy Schubert #define LLONG long int 4162b15cb3dSCy Schubert #endif /* HAVE_LONG_LONG_INT */ 4172b15cb3dSCy Schubert #endif /* !defined(LLONG) */ 4182b15cb3dSCy Schubert 4192b15cb3dSCy Schubert /* Support for intmax_t. */ 4202b15cb3dSCy Schubert #ifndef INTMAX_T 4212b15cb3dSCy Schubert #if HAVE_INTMAX_T || defined(intmax_t) 4222b15cb3dSCy Schubert #define INTMAX_T intmax_t 4232b15cb3dSCy Schubert #else 4242b15cb3dSCy Schubert #define INTMAX_T LLONG 4252b15cb3dSCy Schubert #endif /* HAVE_INTMAX_T || defined(intmax_t) */ 4262b15cb3dSCy Schubert #endif /* !defined(INTMAX_T) */ 4272b15cb3dSCy Schubert 4282b15cb3dSCy Schubert /* Support for uintptr_t. */ 4292b15cb3dSCy Schubert #ifndef UINTPTR_T 4302b15cb3dSCy Schubert #if HAVE_UINTPTR_T || defined(uintptr_t) 4312b15cb3dSCy Schubert #define UINTPTR_T uintptr_t 4322b15cb3dSCy Schubert #else 4332b15cb3dSCy Schubert #define UINTPTR_T unsigned long int 4342b15cb3dSCy Schubert #endif /* HAVE_UINTPTR_T || defined(uintptr_t) */ 4352b15cb3dSCy Schubert #endif /* !defined(UINTPTR_T) */ 4362b15cb3dSCy Schubert 4372b15cb3dSCy Schubert /* Support for ptrdiff_t. */ 4382b15cb3dSCy Schubert #ifndef PTRDIFF_T 4392b15cb3dSCy Schubert #if HAVE_PTRDIFF_T || defined(ptrdiff_t) 4402b15cb3dSCy Schubert #define PTRDIFF_T ptrdiff_t 4412b15cb3dSCy Schubert #else 4422b15cb3dSCy Schubert #define PTRDIFF_T long int 4432b15cb3dSCy Schubert #endif /* HAVE_PTRDIFF_T || defined(ptrdiff_t) */ 4442b15cb3dSCy Schubert #endif /* !defined(PTRDIFF_T) */ 4452b15cb3dSCy Schubert 4462b15cb3dSCy Schubert /* 4472b15cb3dSCy Schubert * We need an unsigned integer type corresponding to ptrdiff_t (cf. C99: 4482b15cb3dSCy Schubert * 7.19.6.1, 7). However, we'll simply use PTRDIFF_T and convert it to an 4492b15cb3dSCy Schubert * unsigned type if necessary. This should work just fine in practice. 4502b15cb3dSCy Schubert */ 4512b15cb3dSCy Schubert #ifndef UPTRDIFF_T 4522b15cb3dSCy Schubert #define UPTRDIFF_T PTRDIFF_T 4532b15cb3dSCy Schubert #endif /* !defined(UPTRDIFF_T) */ 4542b15cb3dSCy Schubert 4552b15cb3dSCy Schubert /* 4562b15cb3dSCy Schubert * We need a signed integer type corresponding to size_t (cf. C99: 7.19.6.1, 7). 4572b15cb3dSCy Schubert * However, we'll simply use size_t and convert it to a signed type if 4582b15cb3dSCy Schubert * necessary. This should work just fine in practice. 4592b15cb3dSCy Schubert */ 4602b15cb3dSCy Schubert #ifndef SSIZE_T 4612b15cb3dSCy Schubert #define SSIZE_T size_t 4622b15cb3dSCy Schubert #endif /* !defined(SSIZE_T) */ 4632b15cb3dSCy Schubert 4642b15cb3dSCy Schubert /* Either ERANGE or E2BIG should be available everywhere. */ 4652b15cb3dSCy Schubert #ifndef ERANGE 4662b15cb3dSCy Schubert #define ERANGE E2BIG 4672b15cb3dSCy Schubert #endif /* !defined(ERANGE) */ 4682b15cb3dSCy Schubert #ifndef EOVERFLOW 4692b15cb3dSCy Schubert #define EOVERFLOW ERANGE 4702b15cb3dSCy Schubert #endif /* !defined(EOVERFLOW) */ 4712b15cb3dSCy Schubert 4722b15cb3dSCy Schubert /* 4732b15cb3dSCy Schubert * Buffer size to hold the octal string representation of UINT128_MAX without 4742b15cb3dSCy Schubert * nul-termination ("3777777777777777777777777777777777777777777"). 4752b15cb3dSCy Schubert */ 4762b15cb3dSCy Schubert #ifdef MAX_CONVERT_LENGTH 4772b15cb3dSCy Schubert #undef MAX_CONVERT_LENGTH 4782b15cb3dSCy Schubert #endif /* defined(MAX_CONVERT_LENGTH) */ 4792b15cb3dSCy Schubert #define MAX_CONVERT_LENGTH 43 4802b15cb3dSCy Schubert 4812b15cb3dSCy Schubert /* Format read states. */ 4822b15cb3dSCy Schubert #define PRINT_S_DEFAULT 0 4832b15cb3dSCy Schubert #define PRINT_S_FLAGS 1 4842b15cb3dSCy Schubert #define PRINT_S_WIDTH 2 4852b15cb3dSCy Schubert #define PRINT_S_DOT 3 4862b15cb3dSCy Schubert #define PRINT_S_PRECISION 4 4872b15cb3dSCy Schubert #define PRINT_S_MOD 5 4882b15cb3dSCy Schubert #define PRINT_S_CONV 6 4892b15cb3dSCy Schubert 4902b15cb3dSCy Schubert /* Format flags. */ 4912b15cb3dSCy Schubert #define PRINT_F_MINUS (1 << 0) 4922b15cb3dSCy Schubert #define PRINT_F_PLUS (1 << 1) 4932b15cb3dSCy Schubert #define PRINT_F_SPACE (1 << 2) 4942b15cb3dSCy Schubert #define PRINT_F_NUM (1 << 3) 4952b15cb3dSCy Schubert #define PRINT_F_ZERO (1 << 4) 4962b15cb3dSCy Schubert #define PRINT_F_QUOTE (1 << 5) 4972b15cb3dSCy Schubert #define PRINT_F_UP (1 << 6) 4982b15cb3dSCy Schubert #define PRINT_F_UNSIGNED (1 << 7) 4992b15cb3dSCy Schubert #define PRINT_F_TYPE_G (1 << 8) 5002b15cb3dSCy Schubert #define PRINT_F_TYPE_E (1 << 9) 5012b15cb3dSCy Schubert 5022b15cb3dSCy Schubert /* Conversion flags. */ 5032b15cb3dSCy Schubert #define PRINT_C_CHAR 1 5042b15cb3dSCy Schubert #define PRINT_C_SHORT 2 5052b15cb3dSCy Schubert #define PRINT_C_LONG 3 5062b15cb3dSCy Schubert #define PRINT_C_LLONG 4 5072b15cb3dSCy Schubert #define PRINT_C_LDOUBLE 5 5082b15cb3dSCy Schubert #define PRINT_C_SIZE 6 5092b15cb3dSCy Schubert #define PRINT_C_PTRDIFF 7 5102b15cb3dSCy Schubert #define PRINT_C_INTMAX 8 5112b15cb3dSCy Schubert 5122b15cb3dSCy Schubert #ifndef MAX 5132b15cb3dSCy Schubert #define MAX(x, y) ((x >= y) ? x : y) 5142b15cb3dSCy Schubert #endif /* !defined(MAX) */ 5152b15cb3dSCy Schubert #ifndef CHARTOINT 5162b15cb3dSCy Schubert #define CHARTOINT(ch) (ch - '0') 5172b15cb3dSCy Schubert #endif /* !defined(CHARTOINT) */ 5182b15cb3dSCy Schubert #ifndef ISDIGIT 5192b15cb3dSCy Schubert #define ISDIGIT(ch) ('0' <= (unsigned char)ch && (unsigned char)ch <= '9') 5202b15cb3dSCy Schubert #endif /* !defined(ISDIGIT) */ 5212b15cb3dSCy Schubert #ifndef ISNAN 5222b15cb3dSCy Schubert #define ISNAN(x) (x != x) 5232b15cb3dSCy Schubert #endif /* !defined(ISNAN) */ 5242b15cb3dSCy Schubert #ifndef ISINF 5252b15cb3dSCy Schubert #define ISINF(x) (x != 0.0 && x + x == x) 5262b15cb3dSCy Schubert #endif /* !defined(ISINF) */ 5272b15cb3dSCy Schubert 5282b15cb3dSCy Schubert #ifdef OUTCHAR 5292b15cb3dSCy Schubert #undef OUTCHAR 5302b15cb3dSCy Schubert #endif /* defined(OUTCHAR) */ 5312b15cb3dSCy Schubert #define OUTCHAR(str, len, size, ch) \ 5322b15cb3dSCy Schubert do { \ 5332b15cb3dSCy Schubert if (len + 1 < size) \ 5342b15cb3dSCy Schubert str[len] = ch; \ 5352b15cb3dSCy Schubert (len)++; \ 5362b15cb3dSCy Schubert } while (/* CONSTCOND */ 0) 5372b15cb3dSCy Schubert 5382b15cb3dSCy Schubert static void fmtstr(char *, size_t *, size_t, const char *, int, int, int); 5392b15cb3dSCy Schubert static void fmtint(char *, size_t *, size_t, INTMAX_T, int, int, int, int); 5402b15cb3dSCy Schubert static void fmtflt(char *, size_t *, size_t, LDOUBLE, int, int, int, int *); 5412b15cb3dSCy Schubert static void printsep(char *, size_t *, size_t); 5422b15cb3dSCy Schubert static int getnumsep(int); 5432b15cb3dSCy Schubert static int getexponent(LDOUBLE); 5442b15cb3dSCy Schubert static int convert(UINTMAX_T, char *, size_t, int, int); 5452b15cb3dSCy Schubert static UINTMAX_T cast(LDOUBLE); 5462b15cb3dSCy Schubert static UINTMAX_T myround(LDOUBLE); 5472b15cb3dSCy Schubert static LDOUBLE mypow10(int); 548224ba2bdSOllivier Robert 549224ba2bdSOllivier Robert int 5502b15cb3dSCy Schubert rpl_vsnprintf(char *str, size_t size, const char *format, va_list args); 5512b15cb3dSCy Schubert 5522b15cb3dSCy Schubert int 5532b15cb3dSCy Schubert rpl_vsnprintf(char *str, size_t size, const char *format, va_list args) 554224ba2bdSOllivier Robert { 5552b15cb3dSCy Schubert LDOUBLE fvalue; 5562b15cb3dSCy Schubert INTMAX_T value; 5572b15cb3dSCy Schubert unsigned char cvalue; 5582b15cb3dSCy Schubert const char *strvalue; 5592b15cb3dSCy Schubert INTMAX_T *intmaxptr; 5602b15cb3dSCy Schubert PTRDIFF_T *ptrdiffptr; 5612b15cb3dSCy Schubert SSIZE_T *sizeptr; 5622b15cb3dSCy Schubert LLONG *llongptr; 5632b15cb3dSCy Schubert long int *longptr; 5642b15cb3dSCy Schubert int *intptr; 5652b15cb3dSCy Schubert short int *shortptr; 5662b15cb3dSCy Schubert signed char *charptr; 5672b15cb3dSCy Schubert size_t len = 0; 5682b15cb3dSCy Schubert int overflow = 0; 5692b15cb3dSCy Schubert int base = 0; 5702b15cb3dSCy Schubert int cflags = 0; 5712b15cb3dSCy Schubert int flags = 0; 5722b15cb3dSCy Schubert int width = 0; 5732b15cb3dSCy Schubert int precision = -1; 5742b15cb3dSCy Schubert int state = PRINT_S_DEFAULT; 5752b15cb3dSCy Schubert char ch = *format++; 5762b15cb3dSCy Schubert 5772b15cb3dSCy Schubert /* 5782b15cb3dSCy Schubert * C99 says: "If `n' is zero, nothing is written, and `s' may be a null 5792b15cb3dSCy Schubert * pointer." (7.19.6.5, 2) We're forgiving and allow a NULL pointer 5802b15cb3dSCy Schubert * even if a size larger than zero was specified. At least NetBSD's 5812b15cb3dSCy Schubert * snprintf(3) does the same, as well as other versions of this file. 5822b15cb3dSCy Schubert * (Though some of these versions will write to a non-NULL buffer even 5832b15cb3dSCy Schubert * if a size of zero was specified, which violates the standard.) 5842b15cb3dSCy Schubert */ 5852b15cb3dSCy Schubert if (str == NULL && size != 0) 5862b15cb3dSCy Schubert size = 0; 5872b15cb3dSCy Schubert 5882b15cb3dSCy Schubert while (ch != '\0') 5892b15cb3dSCy Schubert switch (state) { 5902b15cb3dSCy Schubert case PRINT_S_DEFAULT: 5912b15cb3dSCy Schubert if (ch == '%') 5922b15cb3dSCy Schubert state = PRINT_S_FLAGS; 5932b15cb3dSCy Schubert else 5942b15cb3dSCy Schubert OUTCHAR(str, len, size, ch); 5952b15cb3dSCy Schubert ch = *format++; 5962b15cb3dSCy Schubert break; 5972b15cb3dSCy Schubert case PRINT_S_FLAGS: 5982b15cb3dSCy Schubert switch (ch) { 5992b15cb3dSCy Schubert case '-': 6002b15cb3dSCy Schubert flags |= PRINT_F_MINUS; 6012b15cb3dSCy Schubert ch = *format++; 6022b15cb3dSCy Schubert break; 6032b15cb3dSCy Schubert case '+': 6042b15cb3dSCy Schubert flags |= PRINT_F_PLUS; 6052b15cb3dSCy Schubert ch = *format++; 6062b15cb3dSCy Schubert break; 6072b15cb3dSCy Schubert case ' ': 6082b15cb3dSCy Schubert flags |= PRINT_F_SPACE; 6092b15cb3dSCy Schubert ch = *format++; 6102b15cb3dSCy Schubert break; 6112b15cb3dSCy Schubert case '#': 6122b15cb3dSCy Schubert flags |= PRINT_F_NUM; 6132b15cb3dSCy Schubert ch = *format++; 6142b15cb3dSCy Schubert break; 6152b15cb3dSCy Schubert case '0': 6162b15cb3dSCy Schubert flags |= PRINT_F_ZERO; 6172b15cb3dSCy Schubert ch = *format++; 6182b15cb3dSCy Schubert break; 6192b15cb3dSCy Schubert case '\'': /* SUSv2 flag (not in C99). */ 6202b15cb3dSCy Schubert flags |= PRINT_F_QUOTE; 6212b15cb3dSCy Schubert ch = *format++; 6222b15cb3dSCy Schubert break; 6232b15cb3dSCy Schubert default: 6242b15cb3dSCy Schubert state = PRINT_S_WIDTH; 6252b15cb3dSCy Schubert break; 626224ba2bdSOllivier Robert } 6272b15cb3dSCy Schubert break; 6282b15cb3dSCy Schubert case PRINT_S_WIDTH: 6292b15cb3dSCy Schubert if (ISDIGIT(ch)) { 6302b15cb3dSCy Schubert ch = CHARTOINT(ch); 6312b15cb3dSCy Schubert if (width > (INT_MAX - ch) / 10) { 6322b15cb3dSCy Schubert overflow = 1; 6332b15cb3dSCy Schubert goto out; 6342b15cb3dSCy Schubert } 6352b15cb3dSCy Schubert width = 10 * width + ch; 6362b15cb3dSCy Schubert ch = *format++; 6372b15cb3dSCy Schubert } else if (ch == '*') { 6382b15cb3dSCy Schubert /* 6392b15cb3dSCy Schubert * C99 says: "A negative field width argument is 6402b15cb3dSCy Schubert * taken as a `-' flag followed by a positive 6412b15cb3dSCy Schubert * field width." (7.19.6.1, 5) 6422b15cb3dSCy Schubert */ 6432b15cb3dSCy Schubert if ((width = va_arg(args, int)) < 0) { 6442b15cb3dSCy Schubert flags |= PRINT_F_MINUS; 6452b15cb3dSCy Schubert width = -width; 6462b15cb3dSCy Schubert } 6472b15cb3dSCy Schubert ch = *format++; 6482b15cb3dSCy Schubert state = PRINT_S_DOT; 6492b15cb3dSCy Schubert } else 6502b15cb3dSCy Schubert state = PRINT_S_DOT; 6512b15cb3dSCy Schubert break; 6522b15cb3dSCy Schubert case PRINT_S_DOT: 6532b15cb3dSCy Schubert if (ch == '.') { 6542b15cb3dSCy Schubert state = PRINT_S_PRECISION; 6552b15cb3dSCy Schubert ch = *format++; 6562b15cb3dSCy Schubert } else 6572b15cb3dSCy Schubert state = PRINT_S_MOD; 6582b15cb3dSCy Schubert break; 6592b15cb3dSCy Schubert case PRINT_S_PRECISION: 6602b15cb3dSCy Schubert if (precision == -1) 6612b15cb3dSCy Schubert precision = 0; 6622b15cb3dSCy Schubert if (ISDIGIT(ch)) { 6632b15cb3dSCy Schubert ch = CHARTOINT(ch); 6642b15cb3dSCy Schubert if (precision > (INT_MAX - ch) / 10) { 6652b15cb3dSCy Schubert overflow = 1; 6662b15cb3dSCy Schubert goto out; 6672b15cb3dSCy Schubert } 6682b15cb3dSCy Schubert precision = 10 * precision + ch; 6692b15cb3dSCy Schubert ch = *format++; 6702b15cb3dSCy Schubert } else if (ch == '*') { 6712b15cb3dSCy Schubert /* 6722b15cb3dSCy Schubert * C99 says: "A negative precision argument is 6732b15cb3dSCy Schubert * taken as if the precision were omitted." 6742b15cb3dSCy Schubert * (7.19.6.1, 5) 6752b15cb3dSCy Schubert */ 6762b15cb3dSCy Schubert if ((precision = va_arg(args, int)) < 0) 6772b15cb3dSCy Schubert precision = -1; 6782b15cb3dSCy Schubert ch = *format++; 6792b15cb3dSCy Schubert state = PRINT_S_MOD; 6802b15cb3dSCy Schubert } else 6812b15cb3dSCy Schubert state = PRINT_S_MOD; 6822b15cb3dSCy Schubert break; 6832b15cb3dSCy Schubert case PRINT_S_MOD: 6842b15cb3dSCy Schubert switch (ch) { 6852b15cb3dSCy Schubert case 'h': 6862b15cb3dSCy Schubert ch = *format++; 6872b15cb3dSCy Schubert if (ch == 'h') { /* It's a char. */ 6882b15cb3dSCy Schubert ch = *format++; 6892b15cb3dSCy Schubert cflags = PRINT_C_CHAR; 6902b15cb3dSCy Schubert } else 6912b15cb3dSCy Schubert cflags = PRINT_C_SHORT; 6922b15cb3dSCy Schubert break; 6932b15cb3dSCy Schubert case 'l': 6942b15cb3dSCy Schubert ch = *format++; 6952b15cb3dSCy Schubert if (ch == 'l') { /* It's a long long. */ 6962b15cb3dSCy Schubert ch = *format++; 6972b15cb3dSCy Schubert cflags = PRINT_C_LLONG; 6982b15cb3dSCy Schubert } else 6992b15cb3dSCy Schubert cflags = PRINT_C_LONG; 7002b15cb3dSCy Schubert break; 7012b15cb3dSCy Schubert case 'L': 7022b15cb3dSCy Schubert cflags = PRINT_C_LDOUBLE; 7032b15cb3dSCy Schubert ch = *format++; 7042b15cb3dSCy Schubert break; 7052b15cb3dSCy Schubert case 'j': 7062b15cb3dSCy Schubert cflags = PRINT_C_INTMAX; 7072b15cb3dSCy Schubert ch = *format++; 7082b15cb3dSCy Schubert break; 7092b15cb3dSCy Schubert case 't': 7102b15cb3dSCy Schubert cflags = PRINT_C_PTRDIFF; 7112b15cb3dSCy Schubert ch = *format++; 7122b15cb3dSCy Schubert break; 7132b15cb3dSCy Schubert case 'z': 7142b15cb3dSCy Schubert cflags = PRINT_C_SIZE; 7152b15cb3dSCy Schubert ch = *format++; 7162b15cb3dSCy Schubert break; 7172b15cb3dSCy Schubert } 7182b15cb3dSCy Schubert state = PRINT_S_CONV; 7192b15cb3dSCy Schubert break; 7202b15cb3dSCy Schubert case PRINT_S_CONV: 7212b15cb3dSCy Schubert switch (ch) { 7222b15cb3dSCy Schubert case 'd': 7232b15cb3dSCy Schubert /* FALLTHROUGH */ 7242b15cb3dSCy Schubert case 'i': 7252b15cb3dSCy Schubert switch (cflags) { 7262b15cb3dSCy Schubert case PRINT_C_CHAR: 7272b15cb3dSCy Schubert value = (signed char)va_arg(args, int); 7282b15cb3dSCy Schubert break; 7292b15cb3dSCy Schubert case PRINT_C_SHORT: 7302b15cb3dSCy Schubert value = (short int)va_arg(args, int); 7312b15cb3dSCy Schubert break; 7322b15cb3dSCy Schubert case PRINT_C_LONG: 7332b15cb3dSCy Schubert value = va_arg(args, long int); 7342b15cb3dSCy Schubert break; 7352b15cb3dSCy Schubert case PRINT_C_LLONG: 7362b15cb3dSCy Schubert value = va_arg(args, LLONG); 7372b15cb3dSCy Schubert break; 7382b15cb3dSCy Schubert case PRINT_C_SIZE: 7392b15cb3dSCy Schubert value = va_arg(args, SSIZE_T); 7402b15cb3dSCy Schubert break; 7412b15cb3dSCy Schubert case PRINT_C_INTMAX: 7422b15cb3dSCy Schubert value = va_arg(args, INTMAX_T); 7432b15cb3dSCy Schubert break; 7442b15cb3dSCy Schubert case PRINT_C_PTRDIFF: 7452b15cb3dSCy Schubert value = va_arg(args, PTRDIFF_T); 7462b15cb3dSCy Schubert break; 7472b15cb3dSCy Schubert default: 7482b15cb3dSCy Schubert value = va_arg(args, int); 7492b15cb3dSCy Schubert break; 7502b15cb3dSCy Schubert } 7512b15cb3dSCy Schubert fmtint(str, &len, size, value, 10, width, 7522b15cb3dSCy Schubert precision, flags); 7532b15cb3dSCy Schubert break; 7542b15cb3dSCy Schubert case 'X': 7552b15cb3dSCy Schubert flags |= PRINT_F_UP; 7562b15cb3dSCy Schubert /* FALLTHROUGH */ 7572b15cb3dSCy Schubert case 'x': 7582b15cb3dSCy Schubert base = 16; 7592b15cb3dSCy Schubert /* FALLTHROUGH */ 7602b15cb3dSCy Schubert case 'o': 7612b15cb3dSCy Schubert if (base == 0) 7622b15cb3dSCy Schubert base = 8; 7632b15cb3dSCy Schubert /* FALLTHROUGH */ 7642b15cb3dSCy Schubert case 'u': 7652b15cb3dSCy Schubert if (base == 0) 7662b15cb3dSCy Schubert base = 10; 7672b15cb3dSCy Schubert flags |= PRINT_F_UNSIGNED; 7682b15cb3dSCy Schubert switch (cflags) { 7692b15cb3dSCy Schubert case PRINT_C_CHAR: 7702b15cb3dSCy Schubert value = (unsigned char)va_arg(args, 7712b15cb3dSCy Schubert unsigned int); 7722b15cb3dSCy Schubert break; 7732b15cb3dSCy Schubert case PRINT_C_SHORT: 7742b15cb3dSCy Schubert value = (unsigned short int)va_arg(args, 7752b15cb3dSCy Schubert unsigned int); 7762b15cb3dSCy Schubert break; 7772b15cb3dSCy Schubert case PRINT_C_LONG: 7782b15cb3dSCy Schubert value = va_arg(args, unsigned long int); 7792b15cb3dSCy Schubert break; 7802b15cb3dSCy Schubert case PRINT_C_LLONG: 7812b15cb3dSCy Schubert value = va_arg(args, ULLONG); 7822b15cb3dSCy Schubert break; 7832b15cb3dSCy Schubert case PRINT_C_SIZE: 7842b15cb3dSCy Schubert value = va_arg(args, size_t); 7852b15cb3dSCy Schubert break; 7862b15cb3dSCy Schubert case PRINT_C_INTMAX: 7872b15cb3dSCy Schubert value = va_arg(args, UINTMAX_T); 7882b15cb3dSCy Schubert break; 7892b15cb3dSCy Schubert case PRINT_C_PTRDIFF: 7902b15cb3dSCy Schubert value = va_arg(args, UPTRDIFF_T); 7912b15cb3dSCy Schubert break; 7922b15cb3dSCy Schubert default: 7932b15cb3dSCy Schubert value = va_arg(args, unsigned int); 7942b15cb3dSCy Schubert break; 7952b15cb3dSCy Schubert } 7962b15cb3dSCy Schubert fmtint(str, &len, size, value, base, width, 7972b15cb3dSCy Schubert precision, flags); 7982b15cb3dSCy Schubert break; 7992b15cb3dSCy Schubert case 'A': 8002b15cb3dSCy Schubert /* Not yet supported, we'll use "%F". */ 8012b15cb3dSCy Schubert /* FALLTHROUGH */ 8022b15cb3dSCy Schubert case 'F': 8032b15cb3dSCy Schubert flags |= PRINT_F_UP; 8042b15cb3dSCy Schubert /* FALLTHROUGH */ 8052b15cb3dSCy Schubert case 'a': 8062b15cb3dSCy Schubert /* Not yet supported, we'll use "%f". */ 8072b15cb3dSCy Schubert /* FALLTHROUGH */ 8082b15cb3dSCy Schubert case 'f': 8092b15cb3dSCy Schubert if (cflags == PRINT_C_LDOUBLE) 8102b15cb3dSCy Schubert fvalue = va_arg(args, LDOUBLE); 8112b15cb3dSCy Schubert else 8122b15cb3dSCy Schubert fvalue = va_arg(args, double); 8132b15cb3dSCy Schubert fmtflt(str, &len, size, fvalue, width, 8142b15cb3dSCy Schubert precision, flags, &overflow); 8152b15cb3dSCy Schubert if (overflow) 8162b15cb3dSCy Schubert goto out; 8172b15cb3dSCy Schubert break; 8182b15cb3dSCy Schubert case 'E': 8192b15cb3dSCy Schubert flags |= PRINT_F_UP; 8202b15cb3dSCy Schubert /* FALLTHROUGH */ 8212b15cb3dSCy Schubert case 'e': 8222b15cb3dSCy Schubert flags |= PRINT_F_TYPE_E; 8232b15cb3dSCy Schubert if (cflags == PRINT_C_LDOUBLE) 8242b15cb3dSCy Schubert fvalue = va_arg(args, LDOUBLE); 8252b15cb3dSCy Schubert else 8262b15cb3dSCy Schubert fvalue = va_arg(args, double); 8272b15cb3dSCy Schubert fmtflt(str, &len, size, fvalue, width, 8282b15cb3dSCy Schubert precision, flags, &overflow); 8292b15cb3dSCy Schubert if (overflow) 8302b15cb3dSCy Schubert goto out; 8312b15cb3dSCy Schubert break; 8322b15cb3dSCy Schubert case 'G': 8332b15cb3dSCy Schubert flags |= PRINT_F_UP; 8342b15cb3dSCy Schubert /* FALLTHROUGH */ 8352b15cb3dSCy Schubert case 'g': 8362b15cb3dSCy Schubert flags |= PRINT_F_TYPE_G; 8372b15cb3dSCy Schubert if (cflags == PRINT_C_LDOUBLE) 8382b15cb3dSCy Schubert fvalue = va_arg(args, LDOUBLE); 8392b15cb3dSCy Schubert else 8402b15cb3dSCy Schubert fvalue = va_arg(args, double); 8412b15cb3dSCy Schubert /* 8422b15cb3dSCy Schubert * If the precision is zero, it is treated as 8432b15cb3dSCy Schubert * one (cf. C99: 7.19.6.1, 8). 8442b15cb3dSCy Schubert */ 8452b15cb3dSCy Schubert if (precision == 0) 8462b15cb3dSCy Schubert precision = 1; 8472b15cb3dSCy Schubert fmtflt(str, &len, size, fvalue, width, 8482b15cb3dSCy Schubert precision, flags, &overflow); 8492b15cb3dSCy Schubert if (overflow) 8502b15cb3dSCy Schubert goto out; 8512b15cb3dSCy Schubert break; 8522b15cb3dSCy Schubert case 'c': 8532b15cb3dSCy Schubert cvalue = va_arg(args, int); 8542b15cb3dSCy Schubert OUTCHAR(str, len, size, cvalue); 8552b15cb3dSCy Schubert break; 8562b15cb3dSCy Schubert case 's': 8572b15cb3dSCy Schubert strvalue = va_arg(args, char *); 8582b15cb3dSCy Schubert fmtstr(str, &len, size, strvalue, width, 8592b15cb3dSCy Schubert precision, flags); 8602b15cb3dSCy Schubert break; 8612b15cb3dSCy Schubert case 'p': 8622b15cb3dSCy Schubert /* 8632b15cb3dSCy Schubert * C99 says: "The value of the pointer is 8642b15cb3dSCy Schubert * converted to a sequence of printing 8652b15cb3dSCy Schubert * characters, in an implementation-defined 8662b15cb3dSCy Schubert * manner." (C99: 7.19.6.1, 8) 8672b15cb3dSCy Schubert */ 8682b15cb3dSCy Schubert if ((strvalue = va_arg(args, void *)) == NULL) 8692b15cb3dSCy Schubert /* 8702b15cb3dSCy Schubert * We use the glibc format. BSD prints 8712b15cb3dSCy Schubert * "0x0", SysV "0". 8722b15cb3dSCy Schubert */ 8732b15cb3dSCy Schubert fmtstr(str, &len, size, "(nil)", width, 8742b15cb3dSCy Schubert -1, flags); 8752b15cb3dSCy Schubert else { 8762b15cb3dSCy Schubert /* 8772b15cb3dSCy Schubert * We use the BSD/glibc format. SysV 8782b15cb3dSCy Schubert * omits the "0x" prefix (which we emit 8792b15cb3dSCy Schubert * using the PRINT_F_NUM flag). 8802b15cb3dSCy Schubert */ 8812b15cb3dSCy Schubert flags |= PRINT_F_NUM; 8822b15cb3dSCy Schubert flags |= PRINT_F_UNSIGNED; 8832b15cb3dSCy Schubert fmtint(str, &len, size, 8842b15cb3dSCy Schubert (UINTPTR_T)strvalue, 16, width, 8852b15cb3dSCy Schubert precision, flags); 8862b15cb3dSCy Schubert } 8872b15cb3dSCy Schubert break; 8882b15cb3dSCy Schubert case 'n': 8892b15cb3dSCy Schubert switch (cflags) { 8902b15cb3dSCy Schubert case PRINT_C_CHAR: 8912b15cb3dSCy Schubert charptr = va_arg(args, signed char *); 8923311ff84SXin LI *charptr = (signed char)len; 8932b15cb3dSCy Schubert break; 8942b15cb3dSCy Schubert case PRINT_C_SHORT: 8952b15cb3dSCy Schubert shortptr = va_arg(args, short int *); 8963311ff84SXin LI *shortptr = (short int)len; 8972b15cb3dSCy Schubert break; 8982b15cb3dSCy Schubert case PRINT_C_LONG: 8992b15cb3dSCy Schubert longptr = va_arg(args, long int *); 9003311ff84SXin LI *longptr = (long int)len; 9012b15cb3dSCy Schubert break; 9022b15cb3dSCy Schubert case PRINT_C_LLONG: 9032b15cb3dSCy Schubert llongptr = va_arg(args, LLONG *); 9043311ff84SXin LI *llongptr = (LLONG)len; 9052b15cb3dSCy Schubert break; 9062b15cb3dSCy Schubert case PRINT_C_SIZE: 9072b15cb3dSCy Schubert /* 9082b15cb3dSCy Schubert * C99 says that with the "z" length 9092b15cb3dSCy Schubert * modifier, "a following `n' conversion 9102b15cb3dSCy Schubert * specifier applies to a pointer to a 9112b15cb3dSCy Schubert * signed integer type corresponding to 9122b15cb3dSCy Schubert * size_t argument." (7.19.6.1, 7) 9132b15cb3dSCy Schubert */ 9142b15cb3dSCy Schubert sizeptr = va_arg(args, SSIZE_T *); 9153311ff84SXin LI *sizeptr = (SSIZE_T)len; 9162b15cb3dSCy Schubert break; 9172b15cb3dSCy Schubert case PRINT_C_INTMAX: 9182b15cb3dSCy Schubert intmaxptr = va_arg(args, INTMAX_T *); 9193311ff84SXin LI *intmaxptr = (INTMAX_T)len; 9202b15cb3dSCy Schubert break; 9212b15cb3dSCy Schubert case PRINT_C_PTRDIFF: 9222b15cb3dSCy Schubert ptrdiffptr = va_arg(args, PTRDIFF_T *); 9233311ff84SXin LI *ptrdiffptr = (PTRDIFF_T)len; 9242b15cb3dSCy Schubert break; 9252b15cb3dSCy Schubert default: 9262b15cb3dSCy Schubert intptr = va_arg(args, int *); 9273311ff84SXin LI *intptr = (int)len; 9282b15cb3dSCy Schubert break; 9292b15cb3dSCy Schubert } 9302b15cb3dSCy Schubert break; 9312b15cb3dSCy Schubert case '%': /* Print a "%" character verbatim. */ 9322b15cb3dSCy Schubert OUTCHAR(str, len, size, ch); 9332b15cb3dSCy Schubert break; 9342b15cb3dSCy Schubert default: /* Skip other characters. */ 9352b15cb3dSCy Schubert break; 9362b15cb3dSCy Schubert } 9372b15cb3dSCy Schubert ch = *format++; 9382b15cb3dSCy Schubert state = PRINT_S_DEFAULT; 9392b15cb3dSCy Schubert base = cflags = flags = width = 0; 9402b15cb3dSCy Schubert precision = -1; 9412b15cb3dSCy Schubert break; 9422b15cb3dSCy Schubert } 9432b15cb3dSCy Schubert out: 9442b15cb3dSCy Schubert if (len < size) 9452b15cb3dSCy Schubert str[len] = '\0'; 9462b15cb3dSCy Schubert else if (size > 0) 9472b15cb3dSCy Schubert str[size - 1] = '\0'; 9482b15cb3dSCy Schubert 9492b15cb3dSCy Schubert if (overflow || len >= INT_MAX) { 9502b15cb3dSCy Schubert errno = overflow ? EOVERFLOW : ERANGE; 9512b15cb3dSCy Schubert return -1; 9522b15cb3dSCy Schubert } 9532b15cb3dSCy Schubert return (int)len; 9542b15cb3dSCy Schubert } 9552b15cb3dSCy Schubert 9562b15cb3dSCy Schubert static void 9572b15cb3dSCy Schubert fmtstr(char *str, size_t *len, size_t size, const char *value, int width, 9582b15cb3dSCy Schubert int precision, int flags) 9592b15cb3dSCy Schubert { 9602b15cb3dSCy Schubert int padlen, strln; /* Amount to pad. */ 9612b15cb3dSCy Schubert int noprecision = (precision == -1); 9622b15cb3dSCy Schubert 9632b15cb3dSCy Schubert if (value == NULL) /* We're forgiving. */ 9642b15cb3dSCy Schubert value = "(null)"; 9652b15cb3dSCy Schubert 9662b15cb3dSCy Schubert /* If a precision was specified, don't read the string past it. */ 9672b15cb3dSCy Schubert for (strln = 0; value[strln] != '\0' && 9682b15cb3dSCy Schubert (noprecision || strln < precision); strln++) 9692b15cb3dSCy Schubert continue; 9702b15cb3dSCy Schubert 9712b15cb3dSCy Schubert if ((padlen = width - strln) < 0) 9722b15cb3dSCy Schubert padlen = 0; 9732b15cb3dSCy Schubert if (flags & PRINT_F_MINUS) /* Left justify. */ 9742b15cb3dSCy Schubert padlen = -padlen; 9752b15cb3dSCy Schubert 9762b15cb3dSCy Schubert while (padlen > 0) { /* Leading spaces. */ 9772b15cb3dSCy Schubert OUTCHAR(str, *len, size, ' '); 9782b15cb3dSCy Schubert padlen--; 9792b15cb3dSCy Schubert } 9802b15cb3dSCy Schubert while (*value != '\0' && (noprecision || precision-- > 0)) { 9812b15cb3dSCy Schubert OUTCHAR(str, *len, size, *value); 9822b15cb3dSCy Schubert value++; 9832b15cb3dSCy Schubert } 9842b15cb3dSCy Schubert while (padlen < 0) { /* Trailing spaces. */ 9852b15cb3dSCy Schubert OUTCHAR(str, *len, size, ' '); 9862b15cb3dSCy Schubert padlen++; 9872b15cb3dSCy Schubert } 9882b15cb3dSCy Schubert } 9892b15cb3dSCy Schubert 9902b15cb3dSCy Schubert static void 9912b15cb3dSCy Schubert fmtint(char *str, size_t *len, size_t size, INTMAX_T value, int base, int width, 9922b15cb3dSCy Schubert int precision, int flags) 9932b15cb3dSCy Schubert { 9942b15cb3dSCy Schubert UINTMAX_T uvalue; 9952b15cb3dSCy Schubert char iconvert[MAX_CONVERT_LENGTH]; 9962b15cb3dSCy Schubert char sign = 0; 9972b15cb3dSCy Schubert char hexprefix = 0; 9982b15cb3dSCy Schubert int spadlen = 0; /* Amount to space pad. */ 9992b15cb3dSCy Schubert int zpadlen = 0; /* Amount to zero pad. */ 10002b15cb3dSCy Schubert int pos; 10012b15cb3dSCy Schubert int separators = (flags & PRINT_F_QUOTE); 10022b15cb3dSCy Schubert int noprecision = (precision == -1); 10032b15cb3dSCy Schubert 10042b15cb3dSCy Schubert if (flags & PRINT_F_UNSIGNED) 10052b15cb3dSCy Schubert uvalue = value; 10062b15cb3dSCy Schubert else { 10072b15cb3dSCy Schubert uvalue = (value >= 0) ? value : -value; 10082b15cb3dSCy Schubert if (value < 0) 10092b15cb3dSCy Schubert sign = '-'; 10102b15cb3dSCy Schubert else if (flags & PRINT_F_PLUS) /* Do a sign. */ 10112b15cb3dSCy Schubert sign = '+'; 10122b15cb3dSCy Schubert else if (flags & PRINT_F_SPACE) 10132b15cb3dSCy Schubert sign = ' '; 10142b15cb3dSCy Schubert } 10152b15cb3dSCy Schubert 10162b15cb3dSCy Schubert pos = convert(uvalue, iconvert, sizeof(iconvert), base, 10172b15cb3dSCy Schubert flags & PRINT_F_UP); 10182b15cb3dSCy Schubert 10192b15cb3dSCy Schubert if (flags & PRINT_F_NUM && uvalue != 0) { 10202b15cb3dSCy Schubert /* 10212b15cb3dSCy Schubert * C99 says: "The result is converted to an `alternative form'. 10222b15cb3dSCy Schubert * For `o' conversion, it increases the precision, if and only 10232b15cb3dSCy Schubert * if necessary, to force the first digit of the result to be a 10242b15cb3dSCy Schubert * zero (if the value and precision are both 0, a single 0 is 10252b15cb3dSCy Schubert * printed). For `x' (or `X') conversion, a nonzero result has 10262b15cb3dSCy Schubert * `0x' (or `0X') prefixed to it." (7.19.6.1, 6) 10272b15cb3dSCy Schubert */ 10282b15cb3dSCy Schubert switch (base) { 10292b15cb3dSCy Schubert case 8: 10302b15cb3dSCy Schubert if (precision <= pos) 10312b15cb3dSCy Schubert precision = pos + 1; 10322b15cb3dSCy Schubert break; 10332b15cb3dSCy Schubert case 16: 10342b15cb3dSCy Schubert hexprefix = (flags & PRINT_F_UP) ? 'X' : 'x'; 10352b15cb3dSCy Schubert break; 10362b15cb3dSCy Schubert } 10372b15cb3dSCy Schubert } 10382b15cb3dSCy Schubert 10392b15cb3dSCy Schubert if (separators) /* Get the number of group separators we'll print. */ 10402b15cb3dSCy Schubert separators = getnumsep(pos); 10412b15cb3dSCy Schubert 10422b15cb3dSCy Schubert zpadlen = precision - pos - separators; 10432b15cb3dSCy Schubert spadlen = width /* Minimum field width. */ 10442b15cb3dSCy Schubert - separators /* Number of separators. */ 10452b15cb3dSCy Schubert - MAX(precision, pos) /* Number of integer digits. */ 10462b15cb3dSCy Schubert - ((sign != 0) ? 1 : 0) /* Will we print a sign? */ 10472b15cb3dSCy Schubert - ((hexprefix != 0) ? 2 : 0); /* Will we print a prefix? */ 10482b15cb3dSCy Schubert 10492b15cb3dSCy Schubert if (zpadlen < 0) 10502b15cb3dSCy Schubert zpadlen = 0; 10512b15cb3dSCy Schubert if (spadlen < 0) 10522b15cb3dSCy Schubert spadlen = 0; 10532b15cb3dSCy Schubert 10542b15cb3dSCy Schubert /* 10552b15cb3dSCy Schubert * C99 says: "If the `0' and `-' flags both appear, the `0' flag is 10562b15cb3dSCy Schubert * ignored. For `d', `i', `o', `u', `x', and `X' conversions, if a 10572b15cb3dSCy Schubert * precision is specified, the `0' flag is ignored." (7.19.6.1, 6) 10582b15cb3dSCy Schubert */ 10592b15cb3dSCy Schubert if (flags & PRINT_F_MINUS) /* Left justify. */ 10602b15cb3dSCy Schubert spadlen = -spadlen; 10612b15cb3dSCy Schubert else if (flags & PRINT_F_ZERO && noprecision) { 10622b15cb3dSCy Schubert zpadlen += spadlen; 10632b15cb3dSCy Schubert spadlen = 0; 10642b15cb3dSCy Schubert } 10652b15cb3dSCy Schubert while (spadlen > 0) { /* Leading spaces. */ 10662b15cb3dSCy Schubert OUTCHAR(str, *len, size, ' '); 10672b15cb3dSCy Schubert spadlen--; 10682b15cb3dSCy Schubert } 10692b15cb3dSCy Schubert if (sign != 0) /* Sign. */ 10702b15cb3dSCy Schubert OUTCHAR(str, *len, size, sign); 10712b15cb3dSCy Schubert if (hexprefix != 0) { /* A "0x" or "0X" prefix. */ 10722b15cb3dSCy Schubert OUTCHAR(str, *len, size, '0'); 10732b15cb3dSCy Schubert OUTCHAR(str, *len, size, hexprefix); 10742b15cb3dSCy Schubert } 10752b15cb3dSCy Schubert while (zpadlen > 0) { /* Leading zeros. */ 10762b15cb3dSCy Schubert OUTCHAR(str, *len, size, '0'); 10772b15cb3dSCy Schubert zpadlen--; 10782b15cb3dSCy Schubert } 10792b15cb3dSCy Schubert while (pos > 0) { /* The actual digits. */ 10802b15cb3dSCy Schubert pos--; 10812b15cb3dSCy Schubert OUTCHAR(str, *len, size, iconvert[pos]); 10822b15cb3dSCy Schubert if (separators > 0 && pos > 0 && pos % 3 == 0) 10832b15cb3dSCy Schubert printsep(str, len, size); 10842b15cb3dSCy Schubert } 10852b15cb3dSCy Schubert while (spadlen < 0) { /* Trailing spaces. */ 10862b15cb3dSCy Schubert OUTCHAR(str, *len, size, ' '); 10872b15cb3dSCy Schubert spadlen++; 10882b15cb3dSCy Schubert } 10892b15cb3dSCy Schubert } 10902b15cb3dSCy Schubert 10912b15cb3dSCy Schubert static void 10922b15cb3dSCy Schubert fmtflt(char *str, size_t *len, size_t size, LDOUBLE fvalue, int width, 10932b15cb3dSCy Schubert int precision, int flags, int *overflow) 10942b15cb3dSCy Schubert { 10952b15cb3dSCy Schubert LDOUBLE ufvalue; 10962b15cb3dSCy Schubert UINTMAX_T intpart; 10972b15cb3dSCy Schubert UINTMAX_T fracpart; 10982b15cb3dSCy Schubert UINTMAX_T mask; 10992b15cb3dSCy Schubert const char *infnan = NULL; 11002b15cb3dSCy Schubert char iconvert[MAX_CONVERT_LENGTH]; 11012b15cb3dSCy Schubert char fconvert[MAX_CONVERT_LENGTH]; 11022b15cb3dSCy Schubert char econvert[4]; /* "e-12" (without nul-termination). */ 11032b15cb3dSCy Schubert char esign = 0; 11042b15cb3dSCy Schubert char sign = 0; 11052b15cb3dSCy Schubert int leadfraczeros = 0; 11062b15cb3dSCy Schubert int exponent = 0; 11072b15cb3dSCy Schubert int emitpoint = 0; 11082b15cb3dSCy Schubert int omitzeros = 0; 11092b15cb3dSCy Schubert int omitcount = 0; 11102b15cb3dSCy Schubert int padlen = 0; 11112b15cb3dSCy Schubert int epos = 0; 11122b15cb3dSCy Schubert int fpos = 0; 11132b15cb3dSCy Schubert int ipos = 0; 11142b15cb3dSCy Schubert int separators = (flags & PRINT_F_QUOTE); 11152b15cb3dSCy Schubert int estyle = (flags & PRINT_F_TYPE_E); 11162b15cb3dSCy Schubert #if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT 11172b15cb3dSCy Schubert struct lconv *lc = localeconv(); 11182b15cb3dSCy Schubert #endif /* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */ 11192b15cb3dSCy Schubert 11202b15cb3dSCy Schubert /* 11212b15cb3dSCy Schubert * AIX' man page says the default is 0, but C99 and at least Solaris' 11222b15cb3dSCy Schubert * and NetBSD's man pages say the default is 6, and sprintf(3) on AIX 11232b15cb3dSCy Schubert * defaults to 6. 11242b15cb3dSCy Schubert */ 11252b15cb3dSCy Schubert if (precision == -1) 11262b15cb3dSCy Schubert precision = 6; 11272b15cb3dSCy Schubert 11282b15cb3dSCy Schubert if (fvalue < 0.0) 11292b15cb3dSCy Schubert sign = '-'; 11302b15cb3dSCy Schubert else if (flags & PRINT_F_PLUS) /* Do a sign. */ 11312b15cb3dSCy Schubert sign = '+'; 11322b15cb3dSCy Schubert else if (flags & PRINT_F_SPACE) 11332b15cb3dSCy Schubert sign = ' '; 11342b15cb3dSCy Schubert 11352b15cb3dSCy Schubert if (ISNAN(fvalue)) 11362b15cb3dSCy Schubert infnan = (flags & PRINT_F_UP) ? "NAN" : "nan"; 11372b15cb3dSCy Schubert else if (ISINF(fvalue)) 11382b15cb3dSCy Schubert infnan = (flags & PRINT_F_UP) ? "INF" : "inf"; 11392b15cb3dSCy Schubert 11402b15cb3dSCy Schubert if (infnan != NULL) { 11412b15cb3dSCy Schubert if (sign != 0) 11422b15cb3dSCy Schubert iconvert[ipos++] = sign; 11432b15cb3dSCy Schubert while (*infnan != '\0') 11442b15cb3dSCy Schubert iconvert[ipos++] = *infnan++; 11452b15cb3dSCy Schubert fmtstr(str, len, size, iconvert, width, ipos, flags); 11462b15cb3dSCy Schubert return; 11472b15cb3dSCy Schubert } 11482b15cb3dSCy Schubert 11492b15cb3dSCy Schubert /* "%e" (or "%E") or "%g" (or "%G") conversion. */ 11502b15cb3dSCy Schubert if (flags & PRINT_F_TYPE_E || flags & PRINT_F_TYPE_G) { 11512b15cb3dSCy Schubert if (flags & PRINT_F_TYPE_G) { 11522b15cb3dSCy Schubert /* 11532b15cb3dSCy Schubert * For "%g" (and "%G") conversions, the precision 11542b15cb3dSCy Schubert * specifies the number of significant digits, which 11552b15cb3dSCy Schubert * includes the digits in the integer part. The 11562b15cb3dSCy Schubert * conversion will or will not be using "e-style" (like 11572b15cb3dSCy Schubert * "%e" or "%E" conversions) depending on the precision 11582b15cb3dSCy Schubert * and on the exponent. However, the exponent can be 11592b15cb3dSCy Schubert * affected by rounding the converted value, so we'll 11602b15cb3dSCy Schubert * leave this decision for later. Until then, we'll 11612b15cb3dSCy Schubert * assume that we're going to do an "e-style" conversion 11622b15cb3dSCy Schubert * (in order to get the exponent calculated). For 11632b15cb3dSCy Schubert * "e-style", the precision must be decremented by one. 11642b15cb3dSCy Schubert */ 11652b15cb3dSCy Schubert precision--; 11662b15cb3dSCy Schubert /* 11672b15cb3dSCy Schubert * For "%g" (and "%G") conversions, trailing zeros are 11682b15cb3dSCy Schubert * removed from the fractional portion of the result 11692b15cb3dSCy Schubert * unless the "#" flag was specified. 11702b15cb3dSCy Schubert */ 11712b15cb3dSCy Schubert if (!(flags & PRINT_F_NUM)) 11722b15cb3dSCy Schubert omitzeros = 1; 11732b15cb3dSCy Schubert } 11742b15cb3dSCy Schubert exponent = getexponent(fvalue); 11752b15cb3dSCy Schubert estyle = 1; 11762b15cb3dSCy Schubert } 11772b15cb3dSCy Schubert 11782b15cb3dSCy Schubert again: 11792b15cb3dSCy Schubert /* 11802b15cb3dSCy Schubert * Sorry, we only support 9, 19, or 38 digits (that is, the number of 11812b15cb3dSCy Schubert * digits of the 32-bit, the 64-bit, or the 128-bit UINTMAX_MAX value 11822b15cb3dSCy Schubert * minus one) past the decimal point due to our conversion method. 11832b15cb3dSCy Schubert */ 11842b15cb3dSCy Schubert switch (sizeof(UINTMAX_T)) { 11852b15cb3dSCy Schubert case 16: 11862b15cb3dSCy Schubert if (precision > 38) 11872b15cb3dSCy Schubert precision = 38; 11882b15cb3dSCy Schubert break; 11892b15cb3dSCy Schubert case 8: 11902b15cb3dSCy Schubert if (precision > 19) 11912b15cb3dSCy Schubert precision = 19; 11922b15cb3dSCy Schubert break; 11932b15cb3dSCy Schubert default: 11942b15cb3dSCy Schubert if (precision > 9) 11952b15cb3dSCy Schubert precision = 9; 11962b15cb3dSCy Schubert break; 11972b15cb3dSCy Schubert } 11982b15cb3dSCy Schubert 11992b15cb3dSCy Schubert ufvalue = (fvalue >= 0.0) ? fvalue : -fvalue; 12002b15cb3dSCy Schubert if (estyle) /* We want exactly one integer digit. */ 12012b15cb3dSCy Schubert ufvalue /= mypow10(exponent); 12022b15cb3dSCy Schubert 12032b15cb3dSCy Schubert if ((intpart = cast(ufvalue)) == UINTMAX_MAX) { 12042b15cb3dSCy Schubert *overflow = 1; 12052b15cb3dSCy Schubert return; 12062b15cb3dSCy Schubert } 12072b15cb3dSCy Schubert 12082b15cb3dSCy Schubert /* 12092b15cb3dSCy Schubert * Factor of ten with the number of digits needed for the fractional 12102b15cb3dSCy Schubert * part. For example, if the precision is 3, the mask will be 1000. 12112b15cb3dSCy Schubert */ 12123311ff84SXin LI mask = (UINTMAX_T)mypow10(precision); 12132b15cb3dSCy Schubert /* 12142b15cb3dSCy Schubert * We "cheat" by converting the fractional part to integer by 12152b15cb3dSCy Schubert * multiplying by a factor of ten. 12162b15cb3dSCy Schubert */ 12172b15cb3dSCy Schubert if ((fracpart = myround(mask * (ufvalue - intpart))) >= mask) { 12182b15cb3dSCy Schubert /* 12192b15cb3dSCy Schubert * For example, ufvalue = 2.99962, intpart = 2, and mask = 1000 12202b15cb3dSCy Schubert * (because precision = 3). Now, myround(1000 * 0.99962) will 12212b15cb3dSCy Schubert * return 1000. So, the integer part must be incremented by one 12222b15cb3dSCy Schubert * and the fractional part must be set to zero. 12232b15cb3dSCy Schubert */ 12242b15cb3dSCy Schubert intpart++; 12252b15cb3dSCy Schubert fracpart = 0; 12262b15cb3dSCy Schubert if (estyle && intpart == 10) { 12272b15cb3dSCy Schubert /* 12282b15cb3dSCy Schubert * The value was rounded up to ten, but we only want one 12292b15cb3dSCy Schubert * integer digit if using "e-style". So, the integer 12302b15cb3dSCy Schubert * part must be set to one and the exponent must be 12312b15cb3dSCy Schubert * incremented by one. 12322b15cb3dSCy Schubert */ 12332b15cb3dSCy Schubert intpart = 1; 12342b15cb3dSCy Schubert exponent++; 12352b15cb3dSCy Schubert } 12362b15cb3dSCy Schubert } 12372b15cb3dSCy Schubert 12382b15cb3dSCy Schubert /* 12392b15cb3dSCy Schubert * Now that we know the real exponent, we can check whether or not to 12402b15cb3dSCy Schubert * use "e-style" for "%g" (and "%G") conversions. If we don't need 12412b15cb3dSCy Schubert * "e-style", the precision must be adjusted and the integer and 12422b15cb3dSCy Schubert * fractional parts must be recalculated from the original value. 12432b15cb3dSCy Schubert * 12442b15cb3dSCy Schubert * C99 says: "Let P equal the precision if nonzero, 6 if the precision 12452b15cb3dSCy Schubert * is omitted, or 1 if the precision is zero. Then, if a conversion 12462b15cb3dSCy Schubert * with style `E' would have an exponent of X: 12472b15cb3dSCy Schubert * 12482b15cb3dSCy Schubert * - if P > X >= -4, the conversion is with style `f' (or `F') and 12492b15cb3dSCy Schubert * precision P - (X + 1). 12502b15cb3dSCy Schubert * 12512b15cb3dSCy Schubert * - otherwise, the conversion is with style `e' (or `E') and precision 12522b15cb3dSCy Schubert * P - 1." (7.19.6.1, 8) 12532b15cb3dSCy Schubert * 12542b15cb3dSCy Schubert * Note that we had decremented the precision by one. 12552b15cb3dSCy Schubert */ 12562b15cb3dSCy Schubert if (flags & PRINT_F_TYPE_G && estyle && 12572b15cb3dSCy Schubert precision + 1 > exponent && exponent >= -4) { 12582b15cb3dSCy Schubert precision -= exponent; 12592b15cb3dSCy Schubert estyle = 0; 12602b15cb3dSCy Schubert goto again; 12612b15cb3dSCy Schubert } 12622b15cb3dSCy Schubert 12632b15cb3dSCy Schubert if (estyle) { 12642b15cb3dSCy Schubert if (exponent < 0) { 12652b15cb3dSCy Schubert exponent = -exponent; 12662b15cb3dSCy Schubert esign = '-'; 12672b15cb3dSCy Schubert } else 12682b15cb3dSCy Schubert esign = '+'; 12692b15cb3dSCy Schubert 12702b15cb3dSCy Schubert /* 12712b15cb3dSCy Schubert * Convert the exponent. The sizeof(econvert) is 4. So, the 12722b15cb3dSCy Schubert * econvert buffer can hold e.g. "e+99" and "e-99". We don't 12732b15cb3dSCy Schubert * support an exponent which contains more than two digits. 12742b15cb3dSCy Schubert * Therefore, the following stores are safe. 12752b15cb3dSCy Schubert */ 12762b15cb3dSCy Schubert epos = convert(exponent, econvert, 2, 10, 0); 12772b15cb3dSCy Schubert /* 12782b15cb3dSCy Schubert * C99 says: "The exponent always contains at least two digits, 12792b15cb3dSCy Schubert * and only as many more digits as necessary to represent the 12802b15cb3dSCy Schubert * exponent." (7.19.6.1, 8) 12812b15cb3dSCy Schubert */ 12822b15cb3dSCy Schubert if (epos == 1) 12832b15cb3dSCy Schubert econvert[epos++] = '0'; 12842b15cb3dSCy Schubert econvert[epos++] = esign; 12852b15cb3dSCy Schubert econvert[epos++] = (flags & PRINT_F_UP) ? 'E' : 'e'; 12862b15cb3dSCy Schubert } 12872b15cb3dSCy Schubert 12882b15cb3dSCy Schubert /* Convert the integer part and the fractional part. */ 12892b15cb3dSCy Schubert ipos = convert(intpart, iconvert, sizeof(iconvert), 10, 0); 12902b15cb3dSCy Schubert if (fracpart != 0) /* convert() would return 1 if fracpart == 0. */ 12912b15cb3dSCy Schubert fpos = convert(fracpart, fconvert, sizeof(fconvert), 10, 0); 12922b15cb3dSCy Schubert 12932b15cb3dSCy Schubert leadfraczeros = precision - fpos; 12942b15cb3dSCy Schubert 12952b15cb3dSCy Schubert if (omitzeros) { 12962b15cb3dSCy Schubert if (fpos > 0) /* Omit trailing fractional part zeros. */ 12972b15cb3dSCy Schubert while (omitcount < fpos && fconvert[omitcount] == '0') 12982b15cb3dSCy Schubert omitcount++; 12992b15cb3dSCy Schubert else { /* The fractional part is zero, omit it completely. */ 13002b15cb3dSCy Schubert omitcount = precision; 13012b15cb3dSCy Schubert leadfraczeros = 0; 13022b15cb3dSCy Schubert } 13032b15cb3dSCy Schubert precision -= omitcount; 13042b15cb3dSCy Schubert } 13052b15cb3dSCy Schubert 13062b15cb3dSCy Schubert /* 13072b15cb3dSCy Schubert * Print a decimal point if either the fractional part is non-zero 13082b15cb3dSCy Schubert * and/or the "#" flag was specified. 13092b15cb3dSCy Schubert */ 13102b15cb3dSCy Schubert if (precision > 0 || flags & PRINT_F_NUM) 13112b15cb3dSCy Schubert emitpoint = 1; 13122b15cb3dSCy Schubert if (separators) /* Get the number of group separators we'll print. */ 13132b15cb3dSCy Schubert separators = getnumsep(ipos); 13142b15cb3dSCy Schubert 13152b15cb3dSCy Schubert padlen = width /* Minimum field width. */ 13162b15cb3dSCy Schubert - ipos /* Number of integer digits. */ 13172b15cb3dSCy Schubert - epos /* Number of exponent characters. */ 13182b15cb3dSCy Schubert - precision /* Number of fractional digits. */ 13192b15cb3dSCy Schubert - separators /* Number of group separators. */ 13202b15cb3dSCy Schubert - (emitpoint ? 1 : 0) /* Will we print a decimal point? */ 13212b15cb3dSCy Schubert - ((sign != 0) ? 1 : 0); /* Will we print a sign character? */ 13222b15cb3dSCy Schubert 13232b15cb3dSCy Schubert if (padlen < 0) 13242b15cb3dSCy Schubert padlen = 0; 13252b15cb3dSCy Schubert 13262b15cb3dSCy Schubert /* 13272b15cb3dSCy Schubert * C99 says: "If the `0' and `-' flags both appear, the `0' flag is 13282b15cb3dSCy Schubert * ignored." (7.19.6.1, 6) 13292b15cb3dSCy Schubert */ 13302b15cb3dSCy Schubert if (flags & PRINT_F_MINUS) /* Left justifty. */ 13312b15cb3dSCy Schubert padlen = -padlen; 13322b15cb3dSCy Schubert else if (flags & PRINT_F_ZERO && padlen > 0) { 13332b15cb3dSCy Schubert if (sign != 0) { /* Sign. */ 13342b15cb3dSCy Schubert OUTCHAR(str, *len, size, sign); 13352b15cb3dSCy Schubert sign = 0; 13362b15cb3dSCy Schubert } 13372b15cb3dSCy Schubert while (padlen > 0) { /* Leading zeros. */ 13382b15cb3dSCy Schubert OUTCHAR(str, *len, size, '0'); 13392b15cb3dSCy Schubert padlen--; 13402b15cb3dSCy Schubert } 13412b15cb3dSCy Schubert } 13422b15cb3dSCy Schubert while (padlen > 0) { /* Leading spaces. */ 13432b15cb3dSCy Schubert OUTCHAR(str, *len, size, ' '); 13442b15cb3dSCy Schubert padlen--; 13452b15cb3dSCy Schubert } 13462b15cb3dSCy Schubert if (sign != 0) /* Sign. */ 13472b15cb3dSCy Schubert OUTCHAR(str, *len, size, sign); 13482b15cb3dSCy Schubert while (ipos > 0) { /* Integer part. */ 13492b15cb3dSCy Schubert ipos--; 13502b15cb3dSCy Schubert OUTCHAR(str, *len, size, iconvert[ipos]); 13512b15cb3dSCy Schubert if (separators > 0 && ipos > 0 && ipos % 3 == 0) 13522b15cb3dSCy Schubert printsep(str, len, size); 13532b15cb3dSCy Schubert } 13542b15cb3dSCy Schubert if (emitpoint) { /* Decimal point. */ 13552b15cb3dSCy Schubert #if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT 13562b15cb3dSCy Schubert if (lc->decimal_point != NULL && *lc->decimal_point != '\0') 13572b15cb3dSCy Schubert OUTCHAR(str, *len, size, *lc->decimal_point); 13582b15cb3dSCy Schubert else /* We'll always print some decimal point character. */ 13592b15cb3dSCy Schubert #endif /* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */ 13602b15cb3dSCy Schubert OUTCHAR(str, *len, size, '.'); 13612b15cb3dSCy Schubert } 13622b15cb3dSCy Schubert while (leadfraczeros > 0) { /* Leading fractional part zeros. */ 13632b15cb3dSCy Schubert OUTCHAR(str, *len, size, '0'); 13642b15cb3dSCy Schubert leadfraczeros--; 13652b15cb3dSCy Schubert } 13662b15cb3dSCy Schubert while (fpos > omitcount) { /* The remaining fractional part. */ 13672b15cb3dSCy Schubert fpos--; 13682b15cb3dSCy Schubert OUTCHAR(str, *len, size, fconvert[fpos]); 13692b15cb3dSCy Schubert } 13702b15cb3dSCy Schubert while (epos > 0) { /* Exponent. */ 13712b15cb3dSCy Schubert epos--; 13722b15cb3dSCy Schubert OUTCHAR(str, *len, size, econvert[epos]); 13732b15cb3dSCy Schubert } 13742b15cb3dSCy Schubert while (padlen < 0) { /* Trailing spaces. */ 13752b15cb3dSCy Schubert OUTCHAR(str, *len, size, ' '); 13762b15cb3dSCy Schubert padlen++; 13772b15cb3dSCy Schubert } 13782b15cb3dSCy Schubert } 13792b15cb3dSCy Schubert 13802b15cb3dSCy Schubert static void 13812b15cb3dSCy Schubert printsep(char *str, size_t *len, size_t size) 13822b15cb3dSCy Schubert { 13832b15cb3dSCy Schubert #if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP 13842b15cb3dSCy Schubert struct lconv *lc = localeconv(); 13852b15cb3dSCy Schubert int i; 13862b15cb3dSCy Schubert 13872b15cb3dSCy Schubert if (lc->thousands_sep != NULL) 13882b15cb3dSCy Schubert for (i = 0; lc->thousands_sep[i] != '\0'; i++) 13892b15cb3dSCy Schubert OUTCHAR(str, *len, size, lc->thousands_sep[i]); 13902b15cb3dSCy Schubert else 13912b15cb3dSCy Schubert #endif /* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */ 13922b15cb3dSCy Schubert OUTCHAR(str, *len, size, ','); 13932b15cb3dSCy Schubert } 13942b15cb3dSCy Schubert 13952b15cb3dSCy Schubert static int 13962b15cb3dSCy Schubert getnumsep(int digits) 13972b15cb3dSCy Schubert { 13982b15cb3dSCy Schubert int separators = (digits - ((digits % 3 == 0) ? 1 : 0)) / 3; 13992b15cb3dSCy Schubert #if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP 14002b15cb3dSCy Schubert int strln; 14012b15cb3dSCy Schubert struct lconv *lc = localeconv(); 14022b15cb3dSCy Schubert 14032b15cb3dSCy Schubert /* We support an arbitrary separator length (including zero). */ 14042b15cb3dSCy Schubert if (lc->thousands_sep != NULL) { 14052b15cb3dSCy Schubert for (strln = 0; lc->thousands_sep[strln] != '\0'; strln++) 14062b15cb3dSCy Schubert continue; 14072b15cb3dSCy Schubert separators *= strln; 14082b15cb3dSCy Schubert } 14092b15cb3dSCy Schubert #endif /* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */ 14102b15cb3dSCy Schubert return separators; 14112b15cb3dSCy Schubert } 14122b15cb3dSCy Schubert 14132b15cb3dSCy Schubert static int 14142b15cb3dSCy Schubert getexponent(LDOUBLE value) 14152b15cb3dSCy Schubert { 14162b15cb3dSCy Schubert LDOUBLE tmp = (value >= 0.0) ? value : -value; 14172b15cb3dSCy Schubert int exponent = 0; 14182b15cb3dSCy Schubert 14192b15cb3dSCy Schubert /* 14202b15cb3dSCy Schubert * We check for 99 > exponent > -99 in order to work around possible 14212b15cb3dSCy Schubert * endless loops which could happen (at least) in the second loop (at 14222b15cb3dSCy Schubert * least) if we're called with an infinite value. However, we checked 14232b15cb3dSCy Schubert * for infinity before calling this function using our ISINF() macro, so 14242b15cb3dSCy Schubert * this might be somewhat paranoid. 14252b15cb3dSCy Schubert */ 14262b15cb3dSCy Schubert while (tmp < 1.0 && tmp > 0.0 && --exponent > -99) 14272b15cb3dSCy Schubert tmp *= 10; 14282b15cb3dSCy Schubert while (tmp >= 10.0 && ++exponent < 99) 14292b15cb3dSCy Schubert tmp /= 10; 14302b15cb3dSCy Schubert 14312b15cb3dSCy Schubert return exponent; 14322b15cb3dSCy Schubert } 14332b15cb3dSCy Schubert 14342b15cb3dSCy Schubert static int 14352b15cb3dSCy Schubert convert(UINTMAX_T value, char *buf, size_t size, int base, int caps) 14362b15cb3dSCy Schubert { 14372b15cb3dSCy Schubert const char *digits = caps ? "0123456789ABCDEF" : "0123456789abcdef"; 14382b15cb3dSCy Schubert size_t pos = 0; 14392b15cb3dSCy Schubert 14402b15cb3dSCy Schubert /* We return an unterminated buffer with the digits in reverse order. */ 14412b15cb3dSCy Schubert do { 14422b15cb3dSCy Schubert buf[pos++] = digits[value % base]; 14432b15cb3dSCy Schubert value /= base; 14442b15cb3dSCy Schubert } while (value != 0 && pos < size); 14452b15cb3dSCy Schubert 14462b15cb3dSCy Schubert return (int)pos; 14472b15cb3dSCy Schubert } 14482b15cb3dSCy Schubert 14492b15cb3dSCy Schubert static UINTMAX_T 14502b15cb3dSCy Schubert cast(LDOUBLE value) 14512b15cb3dSCy Schubert { 14522b15cb3dSCy Schubert UINTMAX_T result; 14532b15cb3dSCy Schubert 14542b15cb3dSCy Schubert /* 14552b15cb3dSCy Schubert * We check for ">=" and not for ">" because if UINTMAX_MAX cannot be 14562b15cb3dSCy Schubert * represented exactly as an LDOUBLE value (but is less than LDBL_MAX), 14572b15cb3dSCy Schubert * it may be increased to the nearest higher representable value for the 14582b15cb3dSCy Schubert * comparison (cf. C99: 6.3.1.4, 2). It might then equal the LDOUBLE 14592b15cb3dSCy Schubert * value although converting the latter to UINTMAX_T would overflow. 14602b15cb3dSCy Schubert */ 14612b15cb3dSCy Schubert if (value >= UINTMAX_MAX) 14622b15cb3dSCy Schubert return UINTMAX_MAX; 14632b15cb3dSCy Schubert 14643311ff84SXin LI result = (UINTMAX_T)value; 14652b15cb3dSCy Schubert /* 14662b15cb3dSCy Schubert * At least on NetBSD/sparc64 3.0.2 and 4.99.30, casting long double to 14672b15cb3dSCy Schubert * an integer type converts e.g. 1.9 to 2 instead of 1 (which violates 14682b15cb3dSCy Schubert * the standard). Sigh. 14692b15cb3dSCy Schubert */ 14702b15cb3dSCy Schubert return (result <= value) ? result : result - 1; 14712b15cb3dSCy Schubert } 14722b15cb3dSCy Schubert 14732b15cb3dSCy Schubert static UINTMAX_T 14742b15cb3dSCy Schubert myround(LDOUBLE value) 14752b15cb3dSCy Schubert { 14762b15cb3dSCy Schubert UINTMAX_T intpart = cast(value); 14772b15cb3dSCy Schubert 14782b15cb3dSCy Schubert return ((value -= intpart) < 0.5) ? intpart : intpart + 1; 14792b15cb3dSCy Schubert } 14802b15cb3dSCy Schubert 14812b15cb3dSCy Schubert static LDOUBLE 14822b15cb3dSCy Schubert mypow10(int exponent) 14832b15cb3dSCy Schubert { 14842b15cb3dSCy Schubert LDOUBLE result = 1; 14852b15cb3dSCy Schubert 14862b15cb3dSCy Schubert while (exponent > 0) { 14872b15cb3dSCy Schubert result *= 10; 14882b15cb3dSCy Schubert exponent--; 14892b15cb3dSCy Schubert } 14902b15cb3dSCy Schubert while (exponent < 0) { 14912b15cb3dSCy Schubert result /= 10; 14922b15cb3dSCy Schubert exponent++; 14932b15cb3dSCy Schubert } 14942b15cb3dSCy Schubert return result; 14952b15cb3dSCy Schubert } 14962b15cb3dSCy Schubert #endif /* HW_WANT_RPL_VSNPRINTF */ 14972b15cb3dSCy Schubert 14982b15cb3dSCy Schubert #if HW_WANT_RPL_VASPRINTF 14992b15cb3dSCy Schubert #if NEED_MYMEMCPY 15002b15cb3dSCy Schubert void * 15012b15cb3dSCy Schubert mymemcpy(void *dst, void *src, size_t len) 15022b15cb3dSCy Schubert { 15032b15cb3dSCy Schubert const char *from = src; 15042b15cb3dSCy Schubert char *to = dst; 15052b15cb3dSCy Schubert 15062b15cb3dSCy Schubert /* No need for optimization, we use this only to replace va_copy(3). */ 15072b15cb3dSCy Schubert while (len-- > 0) 15082b15cb3dSCy Schubert *to++ = *from++; 15092b15cb3dSCy Schubert return dst; 15102b15cb3dSCy Schubert } 15112b15cb3dSCy Schubert #endif /* NEED_MYMEMCPY */ 15122b15cb3dSCy Schubert 15132b15cb3dSCy Schubert int 15142b15cb3dSCy Schubert rpl_vasprintf(char **ret, const char *format, va_list ap); 15152b15cb3dSCy Schubert 15162b15cb3dSCy Schubert int 15172b15cb3dSCy Schubert rpl_vasprintf(char **ret, const char *format, va_list ap) 15182b15cb3dSCy Schubert { 15192b15cb3dSCy Schubert size_t size; 15202b15cb3dSCy Schubert int len; 15212b15cb3dSCy Schubert va_list aq; 15222b15cb3dSCy Schubert 15232b15cb3dSCy Schubert VA_COPY(aq, ap); 15242b15cb3dSCy Schubert len = vsnprintf(NULL, 0, format, aq); 15252b15cb3dSCy Schubert VA_END_COPY(aq); 15262b15cb3dSCy Schubert if (len < 0 || (*ret = malloc(size = len + 1)) == NULL) 15272b15cb3dSCy Schubert return -1; 15282b15cb3dSCy Schubert return vsnprintf(*ret, size, format, ap); 15292b15cb3dSCy Schubert } 15302b15cb3dSCy Schubert #endif /* HW_WANT_RPL_VASPRINTF */ 15312b15cb3dSCy Schubert 15322b15cb3dSCy Schubert #if HW_WANT_RPL_SNPRINTF 15332b15cb3dSCy Schubert #if HAVE_STDARG_H 15342b15cb3dSCy Schubert int 15352b15cb3dSCy Schubert rpl_snprintf(char *str, size_t size, const char *format, ...); 15362b15cb3dSCy Schubert 15372b15cb3dSCy Schubert int 15382b15cb3dSCy Schubert rpl_snprintf(char *str, size_t size, const char *format, ...) 1539ce265a54SOllivier Robert #else 15402b15cb3dSCy Schubert int 15412b15cb3dSCy Schubert rpl_snprintf(va_alist) va_dcl 15422b15cb3dSCy Schubert #endif /* HAVE_STDARG_H */ 15432b15cb3dSCy Schubert { 15442b15cb3dSCy Schubert #if !HAVE_STDARG_H 15452b15cb3dSCy Schubert char *str; 15462b15cb3dSCy Schubert size_t size; 15472b15cb3dSCy Schubert char *format; 15482b15cb3dSCy Schubert #endif /* HAVE_STDARG_H */ 15492b15cb3dSCy Schubert va_list ap; 15502b15cb3dSCy Schubert int len; 15512b15cb3dSCy Schubert 15522b15cb3dSCy Schubert VA_START(ap, format); 15532b15cb3dSCy Schubert VA_SHIFT(ap, str, char *); 15542b15cb3dSCy Schubert VA_SHIFT(ap, size, size_t); 15552b15cb3dSCy Schubert VA_SHIFT(ap, format, const char *); 15562b15cb3dSCy Schubert len = vsnprintf(str, size, format, ap); 15572b15cb3dSCy Schubert va_end(ap); 15582b15cb3dSCy Schubert return len; 15592b15cb3dSCy Schubert } 15602b15cb3dSCy Schubert #endif /* HW_WANT_RPL_SNPRINTF */ 15612b15cb3dSCy Schubert 15622b15cb3dSCy Schubert #if HW_WANT_RPL_ASPRINTF 15632b15cb3dSCy Schubert #if HAVE_STDARG_H 15642b15cb3dSCy Schubert int 15652b15cb3dSCy Schubert rpl_asprintf(char **ret, const char *format, ...); 15662b15cb3dSCy Schubert 15672b15cb3dSCy Schubert int 15682b15cb3dSCy Schubert rpl_asprintf(char **ret, const char *format, ...) 15692b15cb3dSCy Schubert #else 15702b15cb3dSCy Schubert int 15712b15cb3dSCy Schubert rpl_asprintf(va_alist) va_dcl 15722b15cb3dSCy Schubert #endif /* HAVE_STDARG_H */ 15732b15cb3dSCy Schubert { 15742b15cb3dSCy Schubert #if !HAVE_STDARG_H 15752b15cb3dSCy Schubert char **ret; 15762b15cb3dSCy Schubert char *format; 15772b15cb3dSCy Schubert #endif /* HAVE_STDARG_H */ 15782b15cb3dSCy Schubert va_list ap; 15792b15cb3dSCy Schubert int len; 15802b15cb3dSCy Schubert 15812b15cb3dSCy Schubert VA_START(ap, format); 15822b15cb3dSCy Schubert VA_SHIFT(ap, ret, char **); 15832b15cb3dSCy Schubert VA_SHIFT(ap, format, const char *); 15842b15cb3dSCy Schubert len = vasprintf(ret, format, ap); 15852b15cb3dSCy Schubert va_end(ap); 15862b15cb3dSCy Schubert return len; 15872b15cb3dSCy Schubert } 15882b15cb3dSCy Schubert #endif /* HW_WANT_RPL_ASPRINTF */ 15892b15cb3dSCy Schubert #else /* Dummy declaration to avoid empty translation unit warnings. */ 1590*f5f40dd6SCy Schubert NONEMPTY_TRANSLATION_UNIT 15912b15cb3dSCy Schubert #endif /* HW_WANT_RPL_SNPRINTF || HW_WANT_RPL_VSNPRINTF || HW_WANT_RPL_ASPRINTF || [...] */ 15922b15cb3dSCy Schubert 15932b15cb3dSCy Schubert #if TEST_SNPRINTF 15942b15cb3dSCy Schubert int 15952b15cb3dSCy Schubert main(void) 15962b15cb3dSCy Schubert { 15972b15cb3dSCy Schubert const char *float_fmt[] = { 15982b15cb3dSCy Schubert /* "%E" and "%e" formats. */ 15992b15cb3dSCy Schubert #if HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX 16002b15cb3dSCy Schubert "%.16e", 16012b15cb3dSCy Schubert "%22.16e", 16022b15cb3dSCy Schubert "%022.16e", 16032b15cb3dSCy Schubert "%-22.16e", 16042b15cb3dSCy Schubert "%#+'022.16e", 16052b15cb3dSCy Schubert #endif /* HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX */ 16062b15cb3dSCy Schubert "foo|%#+0123.9E|bar", 16072b15cb3dSCy Schubert "%-123.9e", 16082b15cb3dSCy Schubert "%123.9e", 16092b15cb3dSCy Schubert "%+23.9e", 16102b15cb3dSCy Schubert "%+05.8e", 16112b15cb3dSCy Schubert "%-05.8e", 16122b15cb3dSCy Schubert "%05.8e", 16132b15cb3dSCy Schubert "%+5.8e", 16142b15cb3dSCy Schubert "%-5.8e", 16152b15cb3dSCy Schubert "% 5.8e", 16162b15cb3dSCy Schubert "%5.8e", 16172b15cb3dSCy Schubert "%+4.9e", 16182b15cb3dSCy Schubert #if !OS_LINUX /* glibc sometimes gets these wrong. */ 16192b15cb3dSCy Schubert "%+#010.0e", 16202b15cb3dSCy Schubert "%#10.1e", 16212b15cb3dSCy Schubert "%10.5e", 16222b15cb3dSCy Schubert "% 10.5e", 16232b15cb3dSCy Schubert "%5.0e", 16242b15cb3dSCy Schubert "%5.e", 16252b15cb3dSCy Schubert "%#5.0e", 16262b15cb3dSCy Schubert "%#5.e", 16272b15cb3dSCy Schubert "%3.2e", 16282b15cb3dSCy Schubert "%3.1e", 16292b15cb3dSCy Schubert "%-1.5e", 16302b15cb3dSCy Schubert "%1.5e", 16312b15cb3dSCy Schubert "%01.3e", 16322b15cb3dSCy Schubert "%1.e", 16332b15cb3dSCy Schubert "%.1e", 16342b15cb3dSCy Schubert "%#.0e", 16352b15cb3dSCy Schubert "%+.0e", 16362b15cb3dSCy Schubert "% .0e", 16372b15cb3dSCy Schubert "%.0e", 16382b15cb3dSCy Schubert "%#.e", 16392b15cb3dSCy Schubert "%+.e", 16402b15cb3dSCy Schubert "% .e", 16412b15cb3dSCy Schubert "%.e", 16422b15cb3dSCy Schubert "%4e", 16432b15cb3dSCy Schubert "%e", 16442b15cb3dSCy Schubert "%E", 16452b15cb3dSCy Schubert #endif /* !OS_LINUX */ 16462b15cb3dSCy Schubert /* "%F" and "%f" formats. */ 16472b15cb3dSCy Schubert #if !OS_BSD && !OS_IRIX 16482b15cb3dSCy Schubert "% '022f", 16492b15cb3dSCy Schubert "%+'022f", 16502b15cb3dSCy Schubert "%-'22f", 16512b15cb3dSCy Schubert "%'22f", 16522b15cb3dSCy Schubert #if HAVE_LONG_LONG_INT 16532b15cb3dSCy Schubert "%.16f", 16542b15cb3dSCy Schubert "%22.16f", 16552b15cb3dSCy Schubert "%022.16f", 16562b15cb3dSCy Schubert "%-22.16f", 16572b15cb3dSCy Schubert "%#+'022.16f", 16582b15cb3dSCy Schubert #endif /* HAVE_LONG_LONG_INT */ 16592b15cb3dSCy Schubert #endif /* !OS_BSD && !OS_IRIX */ 16602b15cb3dSCy Schubert "foo|%#+0123.9F|bar", 16612b15cb3dSCy Schubert "%-123.9f", 16622b15cb3dSCy Schubert "%123.9f", 16632b15cb3dSCy Schubert "%+23.9f", 16642b15cb3dSCy Schubert "%+#010.0f", 16652b15cb3dSCy Schubert "%#10.1f", 16662b15cb3dSCy Schubert "%10.5f", 16672b15cb3dSCy Schubert "% 10.5f", 16682b15cb3dSCy Schubert "%+05.8f", 16692b15cb3dSCy Schubert "%-05.8f", 16702b15cb3dSCy Schubert "%05.8f", 16712b15cb3dSCy Schubert "%+5.8f", 16722b15cb3dSCy Schubert "%-5.8f", 16732b15cb3dSCy Schubert "% 5.8f", 16742b15cb3dSCy Schubert "%5.8f", 16752b15cb3dSCy Schubert "%5.0f", 16762b15cb3dSCy Schubert "%5.f", 16772b15cb3dSCy Schubert "%#5.0f", 16782b15cb3dSCy Schubert "%#5.f", 16792b15cb3dSCy Schubert "%+4.9f", 16802b15cb3dSCy Schubert "%3.2f", 16812b15cb3dSCy Schubert "%3.1f", 16822b15cb3dSCy Schubert "%-1.5f", 16832b15cb3dSCy Schubert "%1.5f", 16842b15cb3dSCy Schubert "%01.3f", 16852b15cb3dSCy Schubert "%1.f", 16862b15cb3dSCy Schubert "%.1f", 16872b15cb3dSCy Schubert "%#.0f", 16882b15cb3dSCy Schubert "%+.0f", 16892b15cb3dSCy Schubert "% .0f", 16902b15cb3dSCy Schubert "%.0f", 16912b15cb3dSCy Schubert "%#.f", 16922b15cb3dSCy Schubert "%+.f", 16932b15cb3dSCy Schubert "% .f", 16942b15cb3dSCy Schubert "%.f", 16952b15cb3dSCy Schubert "%4f", 16962b15cb3dSCy Schubert "%f", 16972b15cb3dSCy Schubert "%F", 16982b15cb3dSCy Schubert /* "%G" and "%g" formats. */ 16992b15cb3dSCy Schubert #if !OS_BSD && !OS_IRIX && !OS_LINUX 17002b15cb3dSCy Schubert "% '022g", 17012b15cb3dSCy Schubert "%+'022g", 17022b15cb3dSCy Schubert "%-'22g", 17032b15cb3dSCy Schubert "%'22g", 17042b15cb3dSCy Schubert #if HAVE_LONG_LONG_INT 17052b15cb3dSCy Schubert "%.16g", 17062b15cb3dSCy Schubert "%22.16g", 17072b15cb3dSCy Schubert "%022.16g", 17082b15cb3dSCy Schubert "%-22.16g", 17092b15cb3dSCy Schubert "%#+'022.16g", 17102b15cb3dSCy Schubert #endif /* HAVE_LONG_LONG_INT */ 17112b15cb3dSCy Schubert #endif /* !OS_BSD && !OS_IRIX && !OS_LINUX */ 17122b15cb3dSCy Schubert "foo|%#+0123.9G|bar", 17132b15cb3dSCy Schubert "%-123.9g", 17142b15cb3dSCy Schubert "%123.9g", 17152b15cb3dSCy Schubert "%+23.9g", 17162b15cb3dSCy Schubert "%+05.8g", 17172b15cb3dSCy Schubert "%-05.8g", 17182b15cb3dSCy Schubert "%05.8g", 17192b15cb3dSCy Schubert "%+5.8g", 17202b15cb3dSCy Schubert "%-5.8g", 17212b15cb3dSCy Schubert "% 5.8g", 17222b15cb3dSCy Schubert "%5.8g", 17232b15cb3dSCy Schubert "%+4.9g", 17242b15cb3dSCy Schubert #if !OS_LINUX /* glibc sometimes gets these wrong. */ 17252b15cb3dSCy Schubert "%+#010.0g", 17262b15cb3dSCy Schubert "%#10.1g", 17272b15cb3dSCy Schubert "%10.5g", 17282b15cb3dSCy Schubert "% 10.5g", 17292b15cb3dSCy Schubert "%5.0g", 17302b15cb3dSCy Schubert "%5.g", 17312b15cb3dSCy Schubert "%#5.0g", 17322b15cb3dSCy Schubert "%#5.g", 17332b15cb3dSCy Schubert "%3.2g", 17342b15cb3dSCy Schubert "%3.1g", 17352b15cb3dSCy Schubert "%-1.5g", 17362b15cb3dSCy Schubert "%1.5g", 17372b15cb3dSCy Schubert "%01.3g", 17382b15cb3dSCy Schubert "%1.g", 17392b15cb3dSCy Schubert "%.1g", 17402b15cb3dSCy Schubert "%#.0g", 17412b15cb3dSCy Schubert "%+.0g", 17422b15cb3dSCy Schubert "% .0g", 17432b15cb3dSCy Schubert "%.0g", 17442b15cb3dSCy Schubert "%#.g", 17452b15cb3dSCy Schubert "%+.g", 17462b15cb3dSCy Schubert "% .g", 17472b15cb3dSCy Schubert "%.g", 17482b15cb3dSCy Schubert "%4g", 17492b15cb3dSCy Schubert "%g", 17502b15cb3dSCy Schubert "%G", 17512b15cb3dSCy Schubert #endif /* !OS_LINUX */ 17522b15cb3dSCy Schubert NULL 17532b15cb3dSCy Schubert }; 17542b15cb3dSCy Schubert double float_val[] = { 17552b15cb3dSCy Schubert -4.136, 17562b15cb3dSCy Schubert -134.52, 17572b15cb3dSCy Schubert -5.04030201, 17582b15cb3dSCy Schubert -3410.01234, 17592b15cb3dSCy Schubert -999999.999999, 17602b15cb3dSCy Schubert -913450.29876, 17612b15cb3dSCy Schubert -913450.2, 17622b15cb3dSCy Schubert -91345.2, 17632b15cb3dSCy Schubert -9134.2, 17642b15cb3dSCy Schubert -913.2, 17652b15cb3dSCy Schubert -91.2, 17662b15cb3dSCy Schubert -9.2, 17672b15cb3dSCy Schubert -9.9, 17682b15cb3dSCy Schubert 4.136, 17692b15cb3dSCy Schubert 134.52, 17702b15cb3dSCy Schubert 5.04030201, 17712b15cb3dSCy Schubert 3410.01234, 17722b15cb3dSCy Schubert 999999.999999, 17732b15cb3dSCy Schubert 913450.29876, 17742b15cb3dSCy Schubert 913450.2, 17752b15cb3dSCy Schubert 91345.2, 17762b15cb3dSCy Schubert 9134.2, 17772b15cb3dSCy Schubert 913.2, 17782b15cb3dSCy Schubert 91.2, 17792b15cb3dSCy Schubert 9.2, 17802b15cb3dSCy Schubert 9.9, 17812b15cb3dSCy Schubert 9.96, 17822b15cb3dSCy Schubert 9.996, 17832b15cb3dSCy Schubert 9.9996, 17842b15cb3dSCy Schubert 9.99996, 17852b15cb3dSCy Schubert 9.999996, 17862b15cb3dSCy Schubert 9.9999996, 17872b15cb3dSCy Schubert 9.99999996, 17882b15cb3dSCy Schubert 0.99999996, 17892b15cb3dSCy Schubert 0.99999999, 17902b15cb3dSCy Schubert 0.09999999, 17912b15cb3dSCy Schubert 0.00999999, 17922b15cb3dSCy Schubert 0.00099999, 17932b15cb3dSCy Schubert 0.00009999, 17942b15cb3dSCy Schubert 0.00000999, 17952b15cb3dSCy Schubert 0.00000099, 17962b15cb3dSCy Schubert 0.00000009, 17972b15cb3dSCy Schubert 0.00000001, 17982b15cb3dSCy Schubert 0.0000001, 17992b15cb3dSCy Schubert 0.000001, 18002b15cb3dSCy Schubert 0.00001, 18012b15cb3dSCy Schubert 0.0001, 18022b15cb3dSCy Schubert 0.001, 18032b15cb3dSCy Schubert 0.01, 18042b15cb3dSCy Schubert 0.1, 18052b15cb3dSCy Schubert 1.0, 18062b15cb3dSCy Schubert 1.5, 18072b15cb3dSCy Schubert -1.5, 18082b15cb3dSCy Schubert -1.0, 18092b15cb3dSCy Schubert -0.1, 18102b15cb3dSCy Schubert #if !OS_BSD /* BSD sometimes gets these wrong. */ 18112b15cb3dSCy Schubert #ifdef INFINITY 18122b15cb3dSCy Schubert INFINITY, 18132b15cb3dSCy Schubert -INFINITY, 18142b15cb3dSCy Schubert #endif /* defined(INFINITY) */ 18152b15cb3dSCy Schubert #ifdef NAN 18162b15cb3dSCy Schubert NAN, 18172b15cb3dSCy Schubert #endif /* defined(NAN) */ 18182b15cb3dSCy Schubert #endif /* !OS_BSD */ 18192b15cb3dSCy Schubert 0 18202b15cb3dSCy Schubert }; 18212b15cb3dSCy Schubert const char *long_fmt[] = { 18222b15cb3dSCy Schubert "foo|%0123ld|bar", 18232b15cb3dSCy Schubert #if !OS_IRIX 18242b15cb3dSCy Schubert "% '0123ld", 18252b15cb3dSCy Schubert "%+'0123ld", 18262b15cb3dSCy Schubert "%-'123ld", 18272b15cb3dSCy Schubert "%'123ld", 18282b15cb3dSCy Schubert #endif /* !OS_IRiX */ 18292b15cb3dSCy Schubert "%123.9ld", 18302b15cb3dSCy Schubert "% 123.9ld", 18312b15cb3dSCy Schubert "%+123.9ld", 18322b15cb3dSCy Schubert "%-123.9ld", 18332b15cb3dSCy Schubert "%0123ld", 18342b15cb3dSCy Schubert "% 0123ld", 18352b15cb3dSCy Schubert "%+0123ld", 18362b15cb3dSCy Schubert "%-0123ld", 18372b15cb3dSCy Schubert "%10.5ld", 18382b15cb3dSCy Schubert "% 10.5ld", 18392b15cb3dSCy Schubert "%+10.5ld", 18402b15cb3dSCy Schubert "%-10.5ld", 18412b15cb3dSCy Schubert "%010ld", 18422b15cb3dSCy Schubert "% 010ld", 18432b15cb3dSCy Schubert "%+010ld", 18442b15cb3dSCy Schubert "%-010ld", 18452b15cb3dSCy Schubert "%4.2ld", 18462b15cb3dSCy Schubert "% 4.2ld", 18472b15cb3dSCy Schubert "%+4.2ld", 18482b15cb3dSCy Schubert "%-4.2ld", 18492b15cb3dSCy Schubert "%04ld", 18502b15cb3dSCy Schubert "% 04ld", 18512b15cb3dSCy Schubert "%+04ld", 18522b15cb3dSCy Schubert "%-04ld", 18532b15cb3dSCy Schubert "%5.5ld", 18542b15cb3dSCy Schubert "%+22.33ld", 18552b15cb3dSCy Schubert "%01.3ld", 18562b15cb3dSCy Schubert "%1.5ld", 18572b15cb3dSCy Schubert "%-1.5ld", 18582b15cb3dSCy Schubert "%44ld", 18592b15cb3dSCy Schubert "%4ld", 18602b15cb3dSCy Schubert "%4.0ld", 18612b15cb3dSCy Schubert "%4.ld", 18622b15cb3dSCy Schubert "%.44ld", 18632b15cb3dSCy Schubert "%.4ld", 18642b15cb3dSCy Schubert "%.0ld", 18652b15cb3dSCy Schubert "%.ld", 18662b15cb3dSCy Schubert "%ld", 18672b15cb3dSCy Schubert NULL 18682b15cb3dSCy Schubert }; 18692b15cb3dSCy Schubert long int long_val[] = { 18702b15cb3dSCy Schubert #ifdef LONG_MAX 18712b15cb3dSCy Schubert LONG_MAX, 18722b15cb3dSCy Schubert #endif /* LONG_MAX */ 18732b15cb3dSCy Schubert #ifdef LONG_MIN 18742b15cb3dSCy Schubert LONG_MIN, 18752b15cb3dSCy Schubert #endif /* LONG_MIN */ 18762b15cb3dSCy Schubert -91340, 18772b15cb3dSCy Schubert 91340, 18782b15cb3dSCy Schubert 341, 18792b15cb3dSCy Schubert 134, 18802b15cb3dSCy Schubert 0203, 18812b15cb3dSCy Schubert -1, 18822b15cb3dSCy Schubert 1, 18832b15cb3dSCy Schubert 0 18842b15cb3dSCy Schubert }; 18852b15cb3dSCy Schubert const char *ulong_fmt[] = { 18862b15cb3dSCy Schubert /* "%u" formats. */ 18872b15cb3dSCy Schubert "foo|%0123lu|bar", 18882b15cb3dSCy Schubert #if !OS_IRIX 18892b15cb3dSCy Schubert "% '0123lu", 18902b15cb3dSCy Schubert "%+'0123lu", 18912b15cb3dSCy Schubert "%-'123lu", 18922b15cb3dSCy Schubert "%'123lu", 18932b15cb3dSCy Schubert #endif /* !OS_IRiX */ 18942b15cb3dSCy Schubert "%123.9lu", 18952b15cb3dSCy Schubert "% 123.9lu", 18962b15cb3dSCy Schubert "%+123.9lu", 18972b15cb3dSCy Schubert "%-123.9lu", 18982b15cb3dSCy Schubert "%0123lu", 18992b15cb3dSCy Schubert "% 0123lu", 19002b15cb3dSCy Schubert "%+0123lu", 19012b15cb3dSCy Schubert "%-0123lu", 19022b15cb3dSCy Schubert "%5.5lu", 19032b15cb3dSCy Schubert "%+22.33lu", 19042b15cb3dSCy Schubert "%01.3lu", 19052b15cb3dSCy Schubert "%1.5lu", 19062b15cb3dSCy Schubert "%-1.5lu", 19072b15cb3dSCy Schubert "%44lu", 19082b15cb3dSCy Schubert "%lu", 19092b15cb3dSCy Schubert /* "%o" formats. */ 19102b15cb3dSCy Schubert "foo|%#0123lo|bar", 19112b15cb3dSCy Schubert "%#123.9lo", 19122b15cb3dSCy Schubert "%# 123.9lo", 19132b15cb3dSCy Schubert "%#+123.9lo", 19142b15cb3dSCy Schubert "%#-123.9lo", 19152b15cb3dSCy Schubert "%#0123lo", 19162b15cb3dSCy Schubert "%# 0123lo", 19172b15cb3dSCy Schubert "%#+0123lo", 19182b15cb3dSCy Schubert "%#-0123lo", 19192b15cb3dSCy Schubert "%#5.5lo", 19202b15cb3dSCy Schubert "%#+22.33lo", 19212b15cb3dSCy Schubert "%#01.3lo", 19222b15cb3dSCy Schubert "%#1.5lo", 19232b15cb3dSCy Schubert "%#-1.5lo", 19242b15cb3dSCy Schubert "%#44lo", 19252b15cb3dSCy Schubert "%#lo", 19262b15cb3dSCy Schubert "%123.9lo", 19272b15cb3dSCy Schubert "% 123.9lo", 19282b15cb3dSCy Schubert "%+123.9lo", 19292b15cb3dSCy Schubert "%-123.9lo", 19302b15cb3dSCy Schubert "%0123lo", 19312b15cb3dSCy Schubert "% 0123lo", 19322b15cb3dSCy Schubert "%+0123lo", 19332b15cb3dSCy Schubert "%-0123lo", 19342b15cb3dSCy Schubert "%5.5lo", 19352b15cb3dSCy Schubert "%+22.33lo", 19362b15cb3dSCy Schubert "%01.3lo", 19372b15cb3dSCy Schubert "%1.5lo", 19382b15cb3dSCy Schubert "%-1.5lo", 19392b15cb3dSCy Schubert "%44lo", 19402b15cb3dSCy Schubert "%lo", 19412b15cb3dSCy Schubert /* "%X" and "%x" formats. */ 19422b15cb3dSCy Schubert "foo|%#0123lX|bar", 19432b15cb3dSCy Schubert "%#123.9lx", 19442b15cb3dSCy Schubert "%# 123.9lx", 19452b15cb3dSCy Schubert "%#+123.9lx", 19462b15cb3dSCy Schubert "%#-123.9lx", 19472b15cb3dSCy Schubert "%#0123lx", 19482b15cb3dSCy Schubert "%# 0123lx", 19492b15cb3dSCy Schubert "%#+0123lx", 19502b15cb3dSCy Schubert "%#-0123lx", 19512b15cb3dSCy Schubert "%#5.5lx", 19522b15cb3dSCy Schubert "%#+22.33lx", 19532b15cb3dSCy Schubert "%#01.3lx", 19542b15cb3dSCy Schubert "%#1.5lx", 19552b15cb3dSCy Schubert "%#-1.5lx", 19562b15cb3dSCy Schubert "%#44lx", 19572b15cb3dSCy Schubert "%#lx", 19582b15cb3dSCy Schubert "%#lX", 19592b15cb3dSCy Schubert "%123.9lx", 19602b15cb3dSCy Schubert "% 123.9lx", 19612b15cb3dSCy Schubert "%+123.9lx", 19622b15cb3dSCy Schubert "%-123.9lx", 19632b15cb3dSCy Schubert "%0123lx", 19642b15cb3dSCy Schubert "% 0123lx", 19652b15cb3dSCy Schubert "%+0123lx", 19662b15cb3dSCy Schubert "%-0123lx", 19672b15cb3dSCy Schubert "%5.5lx", 19682b15cb3dSCy Schubert "%+22.33lx", 19692b15cb3dSCy Schubert "%01.3lx", 19702b15cb3dSCy Schubert "%1.5lx", 19712b15cb3dSCy Schubert "%-1.5lx", 19722b15cb3dSCy Schubert "%44lx", 19732b15cb3dSCy Schubert "%lx", 19742b15cb3dSCy Schubert "%lX", 19752b15cb3dSCy Schubert NULL 19762b15cb3dSCy Schubert }; 19772b15cb3dSCy Schubert unsigned long int ulong_val[] = { 19782b15cb3dSCy Schubert #ifdef ULONG_MAX 19792b15cb3dSCy Schubert ULONG_MAX, 19802b15cb3dSCy Schubert #endif /* ULONG_MAX */ 19812b15cb3dSCy Schubert 91340, 19822b15cb3dSCy Schubert 341, 19832b15cb3dSCy Schubert 134, 19842b15cb3dSCy Schubert 0203, 19852b15cb3dSCy Schubert 1, 19862b15cb3dSCy Schubert 0 19872b15cb3dSCy Schubert }; 19882b15cb3dSCy Schubert const char *llong_fmt[] = { 19892b15cb3dSCy Schubert "foo|%0123lld|bar", 19902b15cb3dSCy Schubert "%123.9lld", 19912b15cb3dSCy Schubert "% 123.9lld", 19922b15cb3dSCy Schubert "%+123.9lld", 19932b15cb3dSCy Schubert "%-123.9lld", 19942b15cb3dSCy Schubert "%0123lld", 19952b15cb3dSCy Schubert "% 0123lld", 19962b15cb3dSCy Schubert "%+0123lld", 19972b15cb3dSCy Schubert "%-0123lld", 19982b15cb3dSCy Schubert "%5.5lld", 19992b15cb3dSCy Schubert "%+22.33lld", 20002b15cb3dSCy Schubert "%01.3lld", 20012b15cb3dSCy Schubert "%1.5lld", 20022b15cb3dSCy Schubert "%-1.5lld", 20032b15cb3dSCy Schubert "%44lld", 20042b15cb3dSCy Schubert "%lld", 20052b15cb3dSCy Schubert NULL 20062b15cb3dSCy Schubert }; 20072b15cb3dSCy Schubert LLONG llong_val[] = { 20082b15cb3dSCy Schubert #ifdef LLONG_MAX 20092b15cb3dSCy Schubert LLONG_MAX, 20102b15cb3dSCy Schubert #endif /* LLONG_MAX */ 20112b15cb3dSCy Schubert #ifdef LLONG_MIN 20122b15cb3dSCy Schubert LLONG_MIN, 20132b15cb3dSCy Schubert #endif /* LLONG_MIN */ 20142b15cb3dSCy Schubert -91340, 20152b15cb3dSCy Schubert 91340, 20162b15cb3dSCy Schubert 341, 20172b15cb3dSCy Schubert 134, 20182b15cb3dSCy Schubert 0203, 20192b15cb3dSCy Schubert -1, 20202b15cb3dSCy Schubert 1, 20212b15cb3dSCy Schubert 0 20222b15cb3dSCy Schubert }; 20232b15cb3dSCy Schubert const char *string_fmt[] = { 20242b15cb3dSCy Schubert "foo|%10.10s|bar", 20252b15cb3dSCy Schubert "%-10.10s", 20262b15cb3dSCy Schubert "%10.10s", 20272b15cb3dSCy Schubert "%10.5s", 20282b15cb3dSCy Schubert "%5.10s", 20292b15cb3dSCy Schubert "%10.1s", 20302b15cb3dSCy Schubert "%1.10s", 20312b15cb3dSCy Schubert "%10.0s", 20322b15cb3dSCy Schubert "%0.10s", 20332b15cb3dSCy Schubert "%-42.5s", 20342b15cb3dSCy Schubert "%2.s", 20352b15cb3dSCy Schubert "%.10s", 20362b15cb3dSCy Schubert "%.1s", 20372b15cb3dSCy Schubert "%.0s", 20382b15cb3dSCy Schubert "%.s", 20392b15cb3dSCy Schubert "%4s", 20402b15cb3dSCy Schubert "%s", 20412b15cb3dSCy Schubert NULL 20422b15cb3dSCy Schubert }; 20432b15cb3dSCy Schubert const char *string_val[] = { 20442b15cb3dSCy Schubert "Hello", 20452b15cb3dSCy Schubert "Hello, world!", 20462b15cb3dSCy Schubert "Sound check: One, two, three.", 20472b15cb3dSCy Schubert "This string is a little longer than the other strings.", 20482b15cb3dSCy Schubert "1", 20492b15cb3dSCy Schubert "", 20502b15cb3dSCy Schubert NULL 20512b15cb3dSCy Schubert }; 20522b15cb3dSCy Schubert #if !OS_SYSV /* SysV uses a different format than we do. */ 20532b15cb3dSCy Schubert const char *pointer_fmt[] = { 20542b15cb3dSCy Schubert "foo|%p|bar", 20552b15cb3dSCy Schubert "%42p", 20562b15cb3dSCy Schubert "%p", 20572b15cb3dSCy Schubert NULL 20582b15cb3dSCy Schubert }; 20592b15cb3dSCy Schubert const char *pointer_val[] = { 20602b15cb3dSCy Schubert *pointer_fmt, 20612b15cb3dSCy Schubert *string_fmt, 20622b15cb3dSCy Schubert *string_val, 20632b15cb3dSCy Schubert NULL 20642b15cb3dSCy Schubert }; 20652b15cb3dSCy Schubert #endif /* !OS_SYSV */ 20662b15cb3dSCy Schubert char buf1[1024], buf2[1024]; 20672b15cb3dSCy Schubert double value, digits = 9.123456789012345678901234567890123456789; 20682b15cb3dSCy Schubert int i, j, r1, r2, failed = 0, num = 0; 20692b15cb3dSCy Schubert 20702b15cb3dSCy Schubert /* 20712b15cb3dSCy Schubert * Use -DTEST_NILS in order to also test the conversion of nil values. Might 20722b15cb3dSCy Schubert * segfault on systems which don't support converting a NULL pointer with "%s" 20732b15cb3dSCy Schubert * and lets some test cases fail against BSD and glibc due to bugs in their 20742b15cb3dSCy Schubert * implementations. 20752b15cb3dSCy Schubert */ 20762b15cb3dSCy Schubert #ifndef TEST_NILS 20772b15cb3dSCy Schubert #define TEST_NILS 0 20782b15cb3dSCy Schubert #elif TEST_NILS 20792b15cb3dSCy Schubert #undef TEST_NILS 20802b15cb3dSCy Schubert #define TEST_NILS 1 20812b15cb3dSCy Schubert #endif /* !defined(TEST_NILS) */ 20822b15cb3dSCy Schubert #ifdef TEST 20832b15cb3dSCy Schubert #undef TEST 20842b15cb3dSCy Schubert #endif /* defined(TEST) */ 20852b15cb3dSCy Schubert #define TEST(fmt, val) \ 20862b15cb3dSCy Schubert do { \ 20872b15cb3dSCy Schubert for (i = 0; fmt[i] != NULL; i++) \ 20882b15cb3dSCy Schubert for (j = 0; j == 0 || val[j - TEST_NILS] != 0; j++) { \ 20892b15cb3dSCy Schubert r1 = sprintf(buf1, fmt[i], val[j]); \ 20902b15cb3dSCy Schubert r2 = snprintf(buf2, sizeof(buf2), fmt[i], val[j]); \ 20912b15cb3dSCy Schubert if (strcmp(buf1, buf2) != 0 || r1 != r2) { \ 20922b15cb3dSCy Schubert (void)printf("Results don't match, " \ 20932b15cb3dSCy Schubert "format string: %s\n" \ 20942b15cb3dSCy Schubert "\t sprintf(3): [%s] (%d)\n" \ 20952b15cb3dSCy Schubert "\tsnprintf(3): [%s] (%d)\n", \ 20962b15cb3dSCy Schubert fmt[i], buf1, r1, buf2, r2); \ 20972b15cb3dSCy Schubert failed++; \ 20982b15cb3dSCy Schubert } \ 20992b15cb3dSCy Schubert num++; \ 21002b15cb3dSCy Schubert } \ 21012b15cb3dSCy Schubert } while (/* CONSTCOND */ 0) 21022b15cb3dSCy Schubert 21032b15cb3dSCy Schubert #if HAVE_LOCALE_H 21042b15cb3dSCy Schubert (void)setlocale(LC_ALL, ""); 21052b15cb3dSCy Schubert #endif /* HAVE_LOCALE_H */ 21062b15cb3dSCy Schubert 21072b15cb3dSCy Schubert (void)puts("Testing our snprintf(3) against your system's sprintf(3)."); 21082b15cb3dSCy Schubert TEST(float_fmt, float_val); 21092b15cb3dSCy Schubert TEST(long_fmt, long_val); 21102b15cb3dSCy Schubert TEST(ulong_fmt, ulong_val); 21112b15cb3dSCy Schubert TEST(llong_fmt, llong_val); 21122b15cb3dSCy Schubert TEST(string_fmt, string_val); 21132b15cb3dSCy Schubert #if !OS_SYSV /* SysV uses a different format than we do. */ 21142b15cb3dSCy Schubert TEST(pointer_fmt, pointer_val); 21152b15cb3dSCy Schubert #endif /* !OS_SYSV */ 21162b15cb3dSCy Schubert (void)printf("Result: %d out of %d tests failed.\n", failed, num); 21172b15cb3dSCy Schubert 21182b15cb3dSCy Schubert (void)fputs("Checking how many digits we support: ", stdout); 21192b15cb3dSCy Schubert for (i = 0; i < 100; i++) { 21202b15cb3dSCy Schubert value = pow(10, i) * digits; 21212b15cb3dSCy Schubert (void)sprintf(buf1, "%.1f", value); 21222b15cb3dSCy Schubert (void)snprintf(buf2, sizeof(buf2), "%.1f", value); 21232b15cb3dSCy Schubert if (strcmp(buf1, buf2) != 0) { 21242b15cb3dSCy Schubert (void)printf("apparently %d.\n", i); 21252b15cb3dSCy Schubert break; 21262b15cb3dSCy Schubert } 21272b15cb3dSCy Schubert } 21282b15cb3dSCy Schubert return (failed == 0) ? 0 : 1; 21292b15cb3dSCy Schubert } 21302b15cb3dSCy Schubert #endif /* TEST_SNPRINTF */ 21312b15cb3dSCy Schubert 21322b15cb3dSCy Schubert /* vim: set joinspaces textwidth=80: */ 2133