1 1.1 christos /* $NetBSD: snprintf.c,v 1.1.1.1 2016/01/13 18:41:48 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.1 christos * snprintf.c - a portable implementation of snprintf 5 1.1 christos * 6 1.1 christos * AUTHOR 7 1.1 christos * Mark Martinec <mark.martinec (at) ijs.si>, April 1999. 8 1.1 christos * 9 1.1 christos * Copyright 1999-2002 Mark Martinec. All rights reserved. 10 1.1 christos * 11 1.1 christos * TERMS AND CONDITIONS 12 1.1 christos * This program is free software; it is dual licensed, the terms of the 13 1.1 christos * "Frontier Artistic License" or the "GNU General Public License" 14 1.1 christos * can be chosen at your discretion. The chosen license then applies 15 1.1 christos * solely and in its entirety. Both licenses come with this Kit. 16 1.1 christos * 17 1.1 christos * This program is distributed in the hope that it will be useful, 18 1.1 christos * but WITHOUT ANY WARRANTY; without even the implied warranty 19 1.1 christos * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 1.1 christos * See the license for more details. 21 1.1 christos * 22 1.1 christos * You should have received a copy of the "Frontier Artistic License" 23 1.1 christos * with this Kit in the file named LICENSE.txt, and the copy of 24 1.1 christos * the "GNU General Public License" in the file named LICENSE-GPL.txt. 25 1.1 christos * If not, I'll be glad to provide one. 26 1.1 christos * 27 1.1 christos * FEATURES 28 1.1 christos * - careful adherence to specs regarding flags, field width and precision; 29 1.1 christos * - good performance for large string handling (large format, large 30 1.1 christos * argument or large paddings). Performance is similar to system's sprintf 31 1.1 christos * and in several cases significantly better (make sure you compile with 32 1.1 christos * optimizations turned on, tell the compiler the code is strict ANSI 33 1.1 christos * if necessary to give it more freedom for optimizations); 34 1.1 christos * - return value semantics per ISO/IEC 9899:1999 ("ISO C99"); 35 1.1 christos * - written in standard ISO/ANSI C - requires an ANSI C compiler; 36 1.1 christos * - works also with non-ASCII 8-bit character sets (e.g. EBCDIC) 37 1.1 christos * provided strings are '\0'-terminated. 38 1.1 christos * 39 1.1 christos * SUPPORTED CONVERSION SPECIFIERS AND DATA TYPES 40 1.1 christos * 41 1.1 christos * This snprintf only supports the following conversion specifiers: 42 1.1 christos * s, c, d, u, o, x, X, p (and synonyms: i, D, U, O - see below) 43 1.1 christos * with flags: '-', '+', ' ', '0' and '#'. 44 1.1 christos * An asterisk is supported for field width and for the precision. 45 1.1 christos * 46 1.1 christos * Length modifiers 'h' (short int), 'l' (long int), 47 1.1 christos * and 'll' (long long int) are supported. 48 1.1 christos * NOTE: 49 1.1 christos * If macro SNPRINTF_LONGLONG_SUPPORT is not defined (default) the 50 1.1 christos * length modifier 'll' is recognized but treated the same as 'l', 51 1.1 christos * which may cause argument value truncation! Defining 52 1.1 christos * SNPRINTF_LONGLONG_SUPPORT requires that your system's sprintf also 53 1.1 christos * handles length modifier 'll'. long long int is a language extension 54 1.1 christos * which may not be portable. 55 1.1 christos * 56 1.1 christos * Conversion of numeric data (conversion specifiers d, u, o, x, X, p) 57 1.1 christos * with length modifiers (none or h, l, ll) is left to the system routine 58 1.1 christos * sprintf, but all handling of flags, field width and precision as well as 59 1.1 christos * c and s conversions is done very carefully by this portable routine. 60 1.1 christos * If a string precision (truncation) is specified (e.g. %.8s) it is 61 1.1 christos * guaranteed the string beyond the specified precision will not be referenced. 62 1.1 christos * 63 1.1 christos * Length modifiers h, l and ll are ignored for c and s conversions (data 64 1.1 christos * types wint_t and wchar_t are not supported). 65 1.1 christos * 66 1.1 christos * The following common synonyms for conversion characters are supported: 67 1.1 christos * - i is a synonym for d 68 1.1 christos * - D is a synonym for ld, explicit length modifiers are ignored 69 1.1 christos * - U is a synonym for lu, explicit length modifiers are ignored 70 1.1 christos * - O is a synonym for lo, explicit length modifiers are ignored 71 1.1 christos * The D, O and U conversion characters are nonstandard, they are supported 72 1.1 christos * for backward compatibility only, and should not be used for new code. 73 1.1 christos * 74 1.1 christos * The following is specifically NOT supported: 75 1.1 christos * - flag ' (thousands' grouping character) is recognized but ignored 76 1.1 christos * - numeric conversion specifiers: f, e, E, g, G and synonym F, 77 1.1 christos * as well as the new a and A conversion specifiers 78 1.1 christos * - length modifier 'L' (long double) and 'q' (quad - use 'll' instead) 79 1.1 christos * - wide character/string conversions: lc, ls, and nonstandard 80 1.1 christos * synonyms C and S 81 1.1 christos * - writeback of converted string length: conversion character n 82 1.1 christos * - the n$ specification for direct reference to n-th argument 83 1.1 christos * - locales 84 1.1 christos * 85 1.1 christos * It is permitted for str_m to be zero, and it is permitted to specify NULL 86 1.1 christos * pointer for resulting string argument if str_m is zero (as per ISO C99). 87 1.1 christos * 88 1.1 christos * The return value is the number of characters which would be generated 89 1.1 christos * for the given input, excluding the trailing null. If this value 90 1.1 christos * is greater or equal to str_m, not all characters from the result 91 1.1 christos * have been stored in str, output bytes beyond the (str_m-1) -th character 92 1.1 christos * are discarded. If str_m is greater than zero it is guaranteed 93 1.1 christos * the resulting string will be null-terminated. 94 1.1 christos * 95 1.1 christos * NOTE that this matches the ISO C99, OpenBSD, and GNU C library 2.1, 96 1.1 christos * but is different from some older and vendor implementations, 97 1.1 christos * and is also different from XPG, XSH5, SUSv2 specifications. 98 1.1 christos * For historical discussion on changes in the semantics and standards 99 1.1 christos * of snprintf see printf(3) man page in the Linux programmers manual. 100 1.1 christos * 101 1.1 christos * Routines asprintf and vasprintf return a pointer (in the ptr argument) 102 1.1 christos * to a buffer sufficiently large to hold the resulting string. This pointer 103 1.1 christos * should be passed to free(3) to release the allocated storage when it is 104 1.1 christos * no longer needed. If sufficient space cannot be allocated, these functions 105 1.1 christos * will return -1 and set ptr to be a NULL pointer. These two routines are a 106 1.1 christos * GNU C library extensions (glibc). 107 1.1 christos * 108 1.1 christos * Routines asnprintf and vasnprintf are similar to asprintf and vasprintf, 109 1.1 christos * yet, like snprintf and vsnprintf counterparts, will write at most str_m-1 110 1.1 christos * characters into the allocated output string, the last character in the 111 1.1 christos * allocated buffer then gets the terminating null. If the formatted string 112 1.1 christos * length (the return value) is greater than or equal to the str_m argument, 113 1.1 christos * the resulting string was truncated and some of the formatted characters 114 1.1 christos * were discarded. These routines present a handy way to limit the amount 115 1.1 christos * of allocated memory to some sane value. 116 1.1 christos * 117 1.1 christos * AVAILABILITY 118 1.1 christos * http://www.ijs.si/software/snprintf/ 119 1.1 christos * 120 1.1 christos * REVISION HISTORY 121 1.1 christos * 1999-04 V0.9 Mark Martinec 122 1.1 christos * - initial version, some modifications after comparing printf 123 1.1 christos * man pages for Digital Unix 4.0, Solaris 2.6 and HPUX 10, 124 1.1 christos * and checking how Perl handles sprintf (differently!); 125 1.1 christos * 1999-04-09 V1.0 Mark Martinec <mark.martinec (at) ijs.si> 126 1.1 christos * - added main test program, fixed remaining inconsistencies, 127 1.1 christos * added optional (long long int) support; 128 1.1 christos * 1999-04-12 V1.1 Mark Martinec <mark.martinec (at) ijs.si> 129 1.1 christos * - support the 'p' conversion (pointer to void); 130 1.1 christos * - if a string precision is specified 131 1.1 christos * make sure the string beyond the specified precision 132 1.1 christos * will not be referenced (e.g. by strlen); 133 1.1 christos * 1999-04-13 V1.2 Mark Martinec <mark.martinec (at) ijs.si> 134 1.1 christos * - support synonyms %D=%ld, %U=%lu, %O=%lo; 135 1.1 christos * - speed up the case of long format string with few conversions; 136 1.1 christos * 1999-06-30 V1.3 Mark Martinec <mark.martinec (at) ijs.si> 137 1.1 christos * - fixed runaway loop (eventually crashing when str_l wraps 138 1.1 christos * beyond 2^31) while copying format string without 139 1.1 christos * conversion specifiers to a buffer that is too short 140 1.1 christos * (thanks to Edwin Young <edwiny (at) autonomy.com> for 141 1.1 christos * spotting the problem); 142 1.1 christos * - added macros PORTABLE_SNPRINTF_VERSION_(MAJOR|MINOR) 143 1.1 christos * to snprintf.h 144 1.1 christos * 2000-02-14 V2.0 (never released) Mark Martinec <mark.martinec (at) ijs.si> 145 1.1 christos * - relaxed license terms: The Artistic License now applies. 146 1.1 christos * You may still apply the GNU GENERAL PUBLIC LICENSE 147 1.1 christos * as was distributed with previous versions, if you prefer; 148 1.1 christos * - changed REVISION HISTORY dates to use ISO 8601 date format; 149 1.1 christos * - added vsnprintf (patch also independently proposed by 150 1.1 christos * Caolan McNamara 2000-05-04, and Keith M Willenson 2000-06-01) 151 1.1 christos * 2000-06-27 V2.1 Mark Martinec <mark.martinec (at) ijs.si> 152 1.1 christos * - removed POSIX check for str_m<1; value 0 for str_m is 153 1.1 christos * allowed by ISO C99 (and GNU C library 2.1) - (pointed out 154 1.1 christos * on 2000-05-04 by Caolan McNamara, caolan@ csn dot ul dot ie). 155 1.1 christos * Besides relaxed license this change in standards adherence 156 1.1 christos * is the main reason to bump up the major version number; 157 1.1 christos * - added nonstandard routines asnprintf, vasnprintf, asprintf, 158 1.1 christos * vasprintf that dynamically allocate storage for the 159 1.1 christos * resulting string; these routines are not compiled by default, 160 1.1 christos * see comments where NEED_V?ASN?PRINTF macros are defined; 161 1.1 christos * - autoconf contributed by Caolan McNamara 162 1.1 christos * 2000-10-06 V2.2 Mark Martinec <mark.martinec (at) ijs.si> 163 1.1 christos * - BUG FIX: the %c conversion used a temporary variable 164 1.1 christos * that was no longer in scope when referenced, 165 1.1 christos * possibly causing incorrect resulting character; 166 1.1 christos * - BUG FIX: make precision and minimal field width unsigned 167 1.1 christos * to handle huge values (2^31 <= n < 2^32) correctly; 168 1.1 christos * also be more careful in the use of signed/unsigned/size_t 169 1.1 christos * internal variables - probably more careful than many 170 1.1 christos * vendor implementations, but there may still be a case 171 1.1 christos * where huge values of str_m, precision or minimal field 172 1.1 christos * could cause incorrect behaviour; 173 1.1 christos * - use separate variables for signed/unsigned arguments, 174 1.1 christos * and for short/int, long, and long long argument lengths 175 1.1 christos * to avoid possible incompatibilities on certain 176 1.1 christos * computer architectures. Also use separate variable 177 1.1 christos * arg_sign to hold sign of a numeric argument, 178 1.1 christos * to make code more transparent; 179 1.1 christos * - some fiddling with zero padding and "0x" to make it 180 1.1 christos * Linux compatible; 181 1.1 christos * - systematically use macros fast_memcpy and fast_memset 182 1.1 christos * instead of case-by-case hand optimization; determine some 183 1.1 christos * breakeven string lengths for different architectures; 184 1.1 christos * - terminology change: 'format' -> 'conversion specifier', 185 1.1 christos * 'C9x' -> 'ISO/IEC 9899:1999 ("ISO C99")', 186 1.1 christos * 'alternative form' -> 'alternate form', 187 1.1 christos * 'data type modifier' -> 'length modifier'; 188 1.1 christos * - several comments rephrased and new ones added; 189 1.1 christos * - make compiler not complain about 'credits' defined but 190 1.1 christos * not used; 191 1.1 christos * 2001-08 V2.3 Mark Martinec <mark.martinec (at) ijs.si> 192 1.1 christos * .. 2002-02 - writeback conversion specifier 'n' is now supported; 193 1.1 christos * - bump the size of a temporary buffer for simple 194 1.1 christos * numeric->string conversion from 32 to 48 characters 195 1.1 christos * in anticipation of 128-bit machines; 196 1.1 christos * - added #include <stddef.h> and <stdarg.h> to snprintf.h; 197 1.1 christos * - fixed one assert in test.c 198 1.1 christos * (thanks to Tuomo A Turunen for reporting this problem); 199 1.1 christos * - portability fix: use isdigit() provided with <ctype.h> 200 1.1 christos * and do not assume character set is ASCII - call strtoul() 201 1.1 christos * if needed to convert field width and precision; 202 1.1 christos * - check for broken or non-ANSI native sprintf (e.g. SunOS) 203 1.1 christos * which does not return string lenth, and work around it; 204 1.1 christos * - shouldn't happen, but just in case (applies to numeric 205 1.1 christos * conversions only): added assertion after a call to 206 1.1 christos * system's sprintf to make sure we detect a problem 207 1.1 christos * as it happens (or very shortly - but still - after a 208 1.1 christos * buffer overflow occured for some strange reason 209 1.1 christos * in system's sprintf); 210 1.1 christos * - cleanup: avoid comparing signed and unsigned values 211 1.1 christos * (ANSI c++ complaint); added a couple of 'const' qualifiers; 212 1.1 christos * - changed few comments, new references to some other 213 1.1 christos * implementations added to the README file; 214 1.1 christos * - it appears the Artistic License and its variant the Frontier 215 1.1 christos * Artistic License are incompatible with GPL and precludes 216 1.1 christos * this work to be included with GPL-licensed work. This was 217 1.1 christos * not my intention. The fact that this package is dual licensed 218 1.1 christos * comes to the rescue. Changed the credits[] string, and 219 1.1 christos * TERMS AND CONDITIONS to explicitly say so, stressing 220 1.1 christos * the fact that this work is dual licensed. 221 1.1 christos */ 222 1.1 christos 223 1.1 christos 224 1.1 christos /* Define HAVE_SNPRINTF if your system already has snprintf and vsnprintf. 225 1.1 christos * 226 1.1 christos * If HAVE_SNPRINTF is defined this module will not produce code for 227 1.1 christos * snprintf and vsnprintf, unless PREFER_PORTABLE_SNPRINTF is defined as well, 228 1.1 christos * causing this portable version of snprintf to be called portable_snprintf 229 1.1 christos * (and portable_vsnprintf). 230 1.1 christos */ 231 1.1 christos /* #define HAVE_SNPRINTF */ 232 1.1 christos 233 1.1 christos /* Define PREFER_PORTABLE_SNPRINTF if your system does have snprintf and 234 1.1 christos * vsnprintf but you would prefer to use the portable routine(s) instead. 235 1.1 christos * In this case the portable routine is declared as portable_snprintf 236 1.1 christos * (and portable_vsnprintf) and a macro 'snprintf' (and 'vsnprintf') 237 1.1 christos * is defined to expand to 'portable_v?snprintf' - see file snprintf.h . 238 1.1 christos * Defining this macro is only useful if HAVE_SNPRINTF is also defined, 239 1.1 christos * but does no harm if defined nevertheless. 240 1.1 christos */ 241 1.1 christos /* #define PREFER_PORTABLE_SNPRINTF */ 242 1.1 christos 243 1.1 christos /* Define SNPRINTF_LONGLONG_SUPPORT if you want to support 244 1.1 christos * data type (long long int) and length modifier 'll' (e.g. %lld). 245 1.1 christos * If undefined, 'll' is recognized but treated as a single 'l'. 246 1.1 christos * 247 1.1 christos * If the system's sprintf does not handle 'll' 248 1.1 christos * the SNPRINTF_LONGLONG_SUPPORT must not be defined! 249 1.1 christos * 250 1.1 christos * This is off by default as (long long int) is a language extension. 251 1.1 christos */ 252 1.1 christos /* #define SNPRINTF_LONGLONG_SUPPORT */ 253 1.1 christos 254 1.1 christos /* Define NEED_SNPRINTF_ONLY if you only need snprintf, and not vsnprintf. 255 1.1 christos * If NEED_SNPRINTF_ONLY is defined, the snprintf will be defined directly, 256 1.1 christos * otherwise both snprintf and vsnprintf routines will be defined 257 1.1 christos * and snprintf will be a simple wrapper around vsnprintf, at the expense 258 1.1 christos * of an extra procedure call. 259 1.1 christos */ 260 1.1 christos /* #define NEED_SNPRINTF_ONLY */ 261 1.1 christos 262 1.1 christos /* Define NEED_V?ASN?PRINTF macros if you need library extension 263 1.1 christos * routines asprintf, vasprintf, asnprintf, vasnprintf respectively, 264 1.1 christos * and your system library does not provide them. They are all small 265 1.1 christos * wrapper routines around portable_vsnprintf. Defining any of the four 266 1.1 christos * NEED_V?ASN?PRINTF macros automatically turns off NEED_SNPRINTF_ONLY 267 1.1 christos * and turns on PREFER_PORTABLE_SNPRINTF. 268 1.1 christos * 269 1.1 christos * Watch for name conflicts with the system library if these routines 270 1.1 christos * are already present there. 271 1.1 christos * 272 1.1 christos * NOTE: vasprintf and vasnprintf routines need va_copy() from stdarg.h, as 273 1.1 christos * specified by C99, to be able to traverse the same list of arguments twice. 274 1.1 christos * I don't know of any other standard and portable way of achieving the same. 275 1.1 christos * With some versions of gcc you may use __va_copy(). You might even get away 276 1.1 christos * with "ap2 = ap", in this case you must not call va_end(ap2) ! 277 1.1 christos * #define va_copy(ap2,ap) __va_copy((ap2),(ap)) 278 1.1 christos * #define va_copy(ap2,ap) (ap2) = (ap) 279 1.1 christos */ 280 1.1 christos /* #define NEED_ASPRINTF */ 281 1.1 christos /* #define NEED_ASNPRINTF */ 282 1.1 christos /* #define NEED_VASPRINTF */ 283 1.1 christos /* #define NEED_VASNPRINTF */ 284 1.1 christos 285 1.1 christos /* Define the following macros if desired: 286 1.1 christos * SOLARIS_COMPATIBLE, SOLARIS_BUG_COMPATIBLE, 287 1.1 christos * HPUX_COMPATIBLE, HPUX_BUG_COMPATIBLE, LINUX_COMPATIBLE, 288 1.1 christos * DIGITAL_UNIX_COMPATIBLE, DIGITAL_UNIX_BUG_COMPATIBLE, 289 1.1 christos * PERL_COMPATIBLE, PERL_BUG_COMPATIBLE, 290 1.1 christos * 291 1.1 christos * - For portable applications it is best not to rely on peculiarities 292 1.1 christos * of a given implementation so it may be best not to define any 293 1.1 christos * of the macros that select compatibility and to avoid features 294 1.1 christos * that vary among the systems. 295 1.1 christos * 296 1.1 christos * - Selecting compatibility with more than one operating system 297 1.1 christos * is not strictly forbidden but is not recommended. 298 1.1 christos * 299 1.1 christos * - 'x'_BUG_COMPATIBLE implies 'x'_COMPATIBLE . 300 1.1 christos * 301 1.1 christos * - 'x'_COMPATIBLE refers to (and enables) a behaviour that is 302 1.1 christos * documented in a sprintf man page on a given operating system 303 1.1 christos * and actually adhered to by the system's sprintf (but not on 304 1.1 christos * most other operating systems). It may also refer to and enable 305 1.1 christos * a behaviour that is declared 'undefined' or 'implementation specific' 306 1.1 christos * in the man page but a given implementation behaves predictably 307 1.1 christos * in a certain way. 308 1.1 christos * 309 1.1 christos * - 'x'_BUG_COMPATIBLE refers to (and enables) a behaviour of system's sprintf 310 1.1 christos * that contradicts the sprintf man page on the same operating system. 311 1.1 christos * 312 1.1 christos * - I do not claim that the 'x'_COMPATIBLE and 'x'_BUG_COMPATIBLE 313 1.1 christos * conditionals take into account all idiosyncrasies of a particular 314 1.1 christos * implementation, there may be other incompatibilities. 315 1.1 christos */ 316 1.1 christos 317 1.1 christos 318 1.1 christos 319 1.1 christos /* ============================================= */ 321 1.1 christos /* NO USER SERVICABLE PARTS FOLLOWING THIS POINT */ 322 1.1 christos /* ============================================= */ 323 1.1 christos 324 1.1 christos #define PORTABLE_SNPRINTF_VERSION_MAJOR 2 325 1.1 christos #define PORTABLE_SNPRINTF_VERSION_MINOR 3 326 1.1 christos 327 1.1 christos #if defined(NEED_ASPRINTF) || defined(NEED_ASNPRINTF) || defined(NEED_VASPRINTF) || defined(NEED_VASNPRINTF) 328 1.1 christos # if defined(NEED_SNPRINTF_ONLY) 329 1.1 christos # undef NEED_SNPRINTF_ONLY 330 1.1 christos # endif 331 1.1 christos # if !defined(PREFER_PORTABLE_SNPRINTF) 332 1.1 christos # define PREFER_PORTABLE_SNPRINTF 333 1.1 christos # endif 334 1.1 christos #endif 335 1.1 christos 336 1.1 christos #if defined(SOLARIS_BUG_COMPATIBLE) && !defined(SOLARIS_COMPATIBLE) 337 1.1 christos #define SOLARIS_COMPATIBLE 338 1.1 christos #endif 339 1.1 christos 340 1.1 christos #if defined(HPUX_BUG_COMPATIBLE) && !defined(HPUX_COMPATIBLE) 341 1.1 christos #define HPUX_COMPATIBLE 342 1.1 christos #endif 343 1.1 christos 344 1.1 christos #if defined(DIGITAL_UNIX_BUG_COMPATIBLE) && !defined(DIGITAL_UNIX_COMPATIBLE) 345 1.1 christos #define DIGITAL_UNIX_COMPATIBLE 346 1.1 christos #endif 347 1.1 christos 348 1.1 christos #if defined(PERL_BUG_COMPATIBLE) && !defined(PERL_COMPATIBLE) 349 1.1 christos #define PERL_COMPATIBLE 350 1.1 christos #endif 351 1.1 christos 352 1.1 christos #if defined(LINUX_BUG_COMPATIBLE) && !defined(LINUX_COMPATIBLE) 353 1.1 christos #define LINUX_COMPATIBLE 354 1.1 christos #endif 355 1.1 christos 356 1.1 christos #include <sys/types.h> 357 1.1 christos #include <ctype.h> 358 1.1 christos #include <string.h> 359 1.1 christos #include <stdlib.h> 360 1.1 christos #include <stdio.h> 361 1.1 christos #include <stdarg.h> 362 1.1 christos #include <assert.h> 363 1.1 christos #include <errno.h> 364 1.1 christos 365 1.1 christos /* For copying strings longer or equal to 'breakeven_point' 366 1.1 christos * it is more efficient to call memcpy() than to do it inline. 367 1.1 christos * The value depends mostly on the processor architecture, 368 1.1 christos * but also on the compiler and its optimization capabilities. 369 1.1 christos * The value is not critical, some small value greater than zero 370 1.1 christos * will be just fine if you don't care to squeeze every drop 371 1.1 christos * of performance out of the code. 372 1.1 christos * 373 1.1 christos * Small values favour memcpy & memset (extra procedure call, less code), 374 1.1 christos * large values favour inline code (saves procedure call, more code). 375 1.1 christos */ 376 1.1 christos #if defined(__alpha__) || defined(__alpha) 377 1.1 christos # define breakeven_point 2 /* AXP (DEC Alpha) - gcc or cc */ 378 1.1 christos #endif 379 1.1 christos #if defined(__i386__) || defined(__i386) 380 1.1 christos # define breakeven_point 15 /* Intel Pentium/Linux - gcc 2.96 (12..30) */ 381 1.1 christos #endif 382 1.1 christos #if defined(__hppa) 383 1.1 christos # define breakeven_point 10 /* HP-PA - gcc */ 384 1.1 christos #endif 385 1.1 christos #if defined(__sparc__) || defined(__sparc) 386 1.1 christos # define breakeven_point 33 /* Sun Sparc 5 - gcc 2.8.1 */ 387 1.1 christos #endif 388 1.1 christos 389 1.1 christos /* some other values of possible interest: */ 390 1.1 christos /* #define breakeven_point 8 */ /* VAX 4000 - vaxc */ 391 1.1 christos /* #define breakeven_point 19 */ /* VAX 4000 - gcc 2.7.0 */ 392 1.1 christos 393 1.1 christos #ifndef breakeven_point 394 1.1 christos # define breakeven_point 6 /* some reasonable one-size-fits-all value */ 395 1.1 christos #endif 396 1.1 christos 397 1.1 christos #define fast_memcpy(d,s,n) \ 398 1.1 christos { register size_t nn = (size_t)(n); \ 399 1.1 christos if (nn >= breakeven_point) memcpy((d), (s), nn); \ 400 1.1 christos else if (nn > 0) { /* call overhead is worth only for large strings*/ \ 401 1.1 christos register char *dd; register const char *ss; \ 402 1.1 christos for (ss=(s), dd=(d); nn>0; nn--) *dd++ = *ss++; } } 403 1.1 christos 404 1.1 christos #define fast_memset(d,c,n) \ 405 1.1 christos { register size_t nn = (size_t)(n); \ 406 1.1 christos if (nn >= breakeven_point) memset((d), (int)(c), nn); \ 407 1.1 christos else if (nn > 0) { /* call overhead is worth only for large strings*/ \ 408 1.1 christos register char *dd; register const int cc=(int)(c); \ 409 1.1 christos for (dd=(d); nn>0; nn--) *dd++ = cc; } } 410 1.1 christos 411 1.1 christos /* The following isdigit() is not portable (e.g. may not work 412 1.1 christos * with non-ASCII character sets). Use the system-provided isdigit() 413 1.1 christos * if available, otherwise uncomment: 414 1.1 christos * #define isdigit(c) ((c) >= '0' && (c) <= '9') 415 1.1 christos */ 416 1.1 christos 417 1.1 christos /* atosizet converts a span of decimal digits to a number of type size_t. 418 1.1 christos * It is a macro, similar to: (but not quite, p will be modified!) 419 1.1 christos * void atosizet(const char *p, const char **endp, size_t *result); 420 1.1 christos * endp will point to just beyond the digits substring. 421 1.1 christos * This is _not_ a general-purpose macro: 422 1.1 christos * - the first argument will be modified; 423 1.1 christos * - the first character must already be checked to be a digit! 424 1.1 christos * NOTE: size_t could be wider than unsigned int; 425 1.1 christos * but we treat numeric string like common implementations do! 426 1.1 christos * If character set is ASCII (checking with a quick and simple-minded test) 427 1.1 christos * we convert string to a number inline for speed, otherwise we call strtoul. 428 1.1 christos */ 429 1.1 christos #define atosizet(p, endp, result) \ 430 1.1 christos if ((int)'0' == 48) { /* a compile-time constant expression, */ \ 431 1.1 christos /* hoping the code from one branch */ \ 432 1.1 christos /* will be optimized away */ \ 433 1.1 christos /* looks like ASCII character set, let's hope it really is */ \ 434 1.1 christos register unsigned int uj = (unsigned int)(*(p)++ - '0'); \ 435 1.1 christos while (isdigit((int)(*(p)))) \ 436 1.1 christos uj = 10*uj + (unsigned int)(*(p)++ - '0'); \ 437 1.1 christos if ((endp) != NULL) *(endp) = (p); \ 438 1.1 christos *(result) = (size_t) uj; \ 439 1.1 christos } else { \ 440 1.1 christos /* non-ASCII character set, play by the rules */ \ 441 1.1 christos char *ep; /* NOTE: no 'const' to make strtoul happy! */ \ 442 1.1 christos /* NOTE: clip (unsigned long) to (unsigned int) as is common !!! */ \ 443 1.1 christos const unsigned int uj = (unsigned int) strtoul((p), &ep, 10); \ 444 1.1 christos /* The following assignment is legal: the address of a non-const */ \ 445 1.1 christos /* object can be assigned to a pointer to a const object, but */ \ 446 1.1 christos /* that pointer cannot be used to alter the value of the object. */ \ 447 1.1 christos if ((endp) != NULL) *(endp) = ep; \ 448 1.1 christos /* if num too large the result will be ULONG_MAX and errno=ERANGE */ \ 449 1.1 christos *(result) = (size_t) uj; \ 450 1.1 christos } \ 451 1.1 christos 452 1.1 christos /* prototypes */ 453 1.1 christos 454 1.1 christos #if defined(NEED_ASPRINTF) 455 1.1 christos int asprintf (char **ptr, const char *fmt, /*args*/ ...); 456 1.1 christos #endif 457 1.1 christos #if defined(NEED_VASPRINTF) 458 1.1 christos int vasprintf (char **ptr, const char *fmt, va_list ap); 459 1.1 christos #endif 460 1.1 christos #if defined(NEED_ASNPRINTF) 461 1.1 christos int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...); 462 1.1 christos #endif 463 1.1 christos #if defined(NEED_VASNPRINTF) 464 1.1 christos int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap); 465 1.1 christos #endif 466 1.1 christos 467 1.1 christos #if defined(HAVE_SNPRINTF) 468 1.1 christos /* declare our portable snprintf routine under name portable_snprintf */ 469 1.1 christos /* declare our portable vsnprintf routine under name portable_vsnprintf */ 470 1.1 christos #else 471 1.1 christos /* declare our portable routines under names snprintf and vsnprintf */ 472 1.1 christos #define portable_snprintf snprintf 473 1.1 christos #if !defined(NEED_SNPRINTF_ONLY) 474 1.1 christos #define portable_vsnprintf vsnprintf 475 1.1 christos #endif 476 1.1 christos #endif 477 1.1 christos 478 1.1 christos #if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF) 479 1.1 christos int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...); 480 1.1 christos #if !defined(NEED_SNPRINTF_ONLY) 481 1.1 christos int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap); 482 1.1 christos #endif 483 1.1 christos #endif 484 1.1 christos 485 1.1 christos /* declarations */ 486 1.1 christos 487 1.1 christos static const char credits[] = "\n\ 488 1.1 christos @(#)snprintf.c, v2.3: Mark Martinec, <mark.martinec (at) ijs.si>\n\ 489 1.1 christos @(#)snprintf.c, v2.3: Copyright 1999-2002 Mark Martinec. Dual licensed: Frontier Artistic License or GNU General Public License applies.\n\ 490 1.1 christos @(#)snprintf.c, v2.3: http://www.ijs.si/software/snprintf/\n"; 491 1.1 christos 492 1.1 christos #if defined(NEED_ASPRINTF) 493 1.1 christos int asprintf(char **ptr, const char *fmt, /*args*/ ...) { 494 1.1 christos va_list ap; 495 1.1 christos size_t str_m; 496 1.1 christos int str_l; 497 1.1 christos 498 1.1 christos *ptr = NULL; 499 1.1 christos va_start(ap, fmt); /* measure the required size */ 500 1.1 christos str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap); 501 1.1 christos va_end(ap); 502 1.1 christos assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ 503 1.1 christos *ptr = (char *) malloc(str_m = (size_t)str_l + 1); 504 1.1 christos if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } 505 1.1 christos else { 506 1.1 christos int str_l2; 507 1.1 christos va_start(ap, fmt); 508 1.1 christos str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); 509 1.1 christos va_end(ap); 510 1.1 christos assert(str_l2 == str_l); 511 1.1 christos } 512 1.1 christos return str_l; 513 1.1 christos } 514 1.1 christos #endif 515 1.1 christos 516 1.1 christos #if defined(NEED_VASPRINTF) 517 1.1 christos int vasprintf(char **ptr, const char *fmt, va_list ap) { 518 1.1 christos size_t str_m; 519 1.1 christos int str_l; 520 1.1 christos 521 1.1 christos *ptr = NULL; 522 1.1 christos { va_list ap2; 523 1.1 christos va_copy(ap2, ap); /* don't consume the original ap, we'll need it again */ 524 1.1 christos str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/ 525 1.1 christos va_end(ap2); 526 1.1 christos } 527 1.1 christos assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ 528 1.1 christos *ptr = (char *) malloc(str_m = (size_t)str_l + 1); 529 1.1 christos if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } 530 1.1 christos else { 531 1.1 christos const int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); 532 1.1 christos assert(str_l2 == str_l); 533 1.1 christos } 534 1.1 christos return str_l; 535 1.1 christos } 536 1.1 christos #endif 537 1.1 christos 538 1.1 christos #if defined(NEED_ASNPRINTF) 539 1.1 christos int asnprintf(char **ptr, size_t str_m, const char *fmt, /*args*/ ...) { 540 1.1 christos va_list ap; 541 1.1 christos int str_l; 542 1.1 christos 543 1.1 christos *ptr = NULL; 544 1.1 christos va_start(ap, fmt); /* measure the required size */ 545 1.1 christos str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap); 546 1.1 christos va_end(ap); 547 1.1 christos assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ 548 1.1 christos if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1; /* truncate */ 549 1.1 christos /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */ 550 1.1 christos if (str_m == 0) { /* not interested in resulting string, just return size */ 551 1.1 christos } else { 552 1.1 christos *ptr = (char *) malloc(str_m); 553 1.1 christos if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } 554 1.1 christos else { 555 1.1 christos int str_l2; 556 1.1 christos va_start(ap, fmt); 557 1.1 christos str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); 558 1.1 christos va_end(ap); 559 1.1 christos assert(str_l2 == str_l); 560 1.1 christos } 561 1.1 christos } 562 1.1 christos return str_l; 563 1.1 christos } 564 1.1 christos #endif 565 1.1 christos 566 1.1 christos #if defined(NEED_VASNPRINTF) 567 1.1 christos int vasnprintf(char **ptr, size_t str_m, const char *fmt, va_list ap) { 568 1.1 christos int str_l; 569 1.1 christos 570 1.1 christos *ptr = NULL; 571 1.1 christos { va_list ap2; 572 1.1 christos va_copy(ap2, ap); /* don't consume the original ap, we'll need it again */ 573 1.1 christos str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/ 574 1.1 christos va_end(ap2); 575 1.1 christos } 576 1.1 christos assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ 577 1.1 christos if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1; /* truncate */ 578 1.1 christos /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */ 579 1.1 christos if (str_m == 0) { /* not interested in resulting string, just return size */ 580 1.1 christos } else { 581 1.1 christos *ptr = (char *) malloc(str_m); 582 1.1 christos if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } 583 1.1 christos else { 584 1.1 christos const int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); 585 1.1 christos assert(str_l2 == str_l); 586 1.1 christos } 587 1.1 christos } 588 1.1 christos return str_l; 589 1.1 christos } 590 1.1 christos #endif 591 1.1 christos 592 1.1 christos /* 593 1.1 christos * If the system does have snprintf and the portable routine is not 594 1.1 christos * specifically required, this module produces no code for snprintf/vsnprintf. 595 1.1 christos */ 596 1.1 christos #if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF) 597 1.1 christos 598 1.1 christos #if !defined(NEED_SNPRINTF_ONLY) 599 1.1 christos int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) { 600 1.1 christos va_list ap; 601 1.1 christos int str_l; 602 1.1 christos 603 1.1 christos va_start(ap, fmt); 604 1.1 christos str_l = portable_vsnprintf(str, str_m, fmt, ap); 605 1.1 christos va_end(ap); 606 1.1 christos return str_l; 607 1.1 christos } 608 1.1 christos #endif 609 1.1 christos 610 1.1 christos #if defined(NEED_SNPRINTF_ONLY) 611 1.1 christos int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) { 612 1.1 christos #else 613 1.1 christos int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) { 614 1.1 christos #endif 615 1.1 christos 616 1.1 christos #if defined(NEED_SNPRINTF_ONLY) 617 1.1 christos va_list ap; 618 1.1 christos #endif 619 1.1 christos size_t str_l = 0; 620 1.1 christos const char *p = fmt; 621 1.1 christos 622 1.1 christos /* In contrast to POSIX, the ISO C99 now says 623 1.1 christos * that str can be NULL and str_m can be 0. 624 1.1 christos * This is more useful than the old: if (str_m < 1) return -1; */ 625 1.1 christos 626 1.1 christos #if defined(NEED_SNPRINTF_ONLY) 627 1.1 christos va_start(ap, fmt); 628 1.1 christos #endif 629 1.1 christos if (!p) p = ""; 630 1.1 christos while (*p) { 631 1.1 christos if (*p != '%') { 632 1.1 christos if (0) { /* compile time decision between two equivalent alternatives */ 633 1.1 christos /* this is simple but slow */ 634 1.1 christos if (str_l < str_m) str[str_l] = *p; 635 1.1 christos p++; str_l++; 636 1.1 christos } else { 637 1.1 christos /* this usually achieves much better performance for cases 638 1.1 christos * where format string is long and contains few conversions */ 639 1.1 christos const char *const q = strchr(p+1,'%'); 640 1.1 christos const size_t n = !q ? strlen(p) : (q-p); 641 1.1 christos if (str_l < str_m) { 642 1.1 christos const size_t avail = str_m-str_l; 643 1.1 christos fast_memcpy(str+str_l, p, (n>avail?avail:n)); 644 1.1 christos } 645 1.1 christos p += n; str_l += n; 646 1.1 christos } 647 1.1 christos } else { 648 1.1 christos const char *starting_p; 649 1.1 christos size_t min_field_width = 0, precision = 0; 650 1.1 christos int zero_padding = 0, precision_specified = 0, justify_left = 0; 651 1.1 christos int alternate_form = 0, force_sign = 0; 652 1.1 christos int space_for_positive = 1; /* If both the ' ' and '+' flags appear, 653 1.1 christos the ' ' flag should be ignored. */ 654 1.1 christos char length_modifier = '\0'; /* allowed values: \0, h, l, L */ 655 1.1 christos char tmp[48];/* temporary buffer for simple numeric->string conversion */ 656 1.1 christos 657 1.1 christos const char *str_arg; /* string address in case of string argument */ 658 1.1 christos size_t str_arg_l; /* natural field width of arg without padding 659 1.1 christos and sign */ 660 1.1 christos unsigned char uchar_arg; 661 1.1 christos /* unsigned char argument value - only defined for c conversion. 662 1.1 christos N.B. standard explicitly states the char argument for 663 1.1 christos the c conversion is unsigned */ 664 1.1 christos 665 1.1 christos size_t number_of_zeros_to_pad = 0; 666 1.1 christos /* number of zeros to be inserted for numeric conversions 667 1.1 christos as required by the precision or minimal field width */ 668 1.1 christos 669 1.1 christos size_t zero_padding_insertion_ind = 0; 670 1.1 christos /* index into tmp where zero padding is to be inserted */ 671 1.1 christos 672 1.1 christos char fmt_spec = '\0'; 673 1.1 christos /* current conversion specifier character */ 674 1.1 christos 675 1.1 christos str_arg = credits;/* just to make compiler happy (defined but not used)*/ 676 1.1 christos str_arg = NULL; 677 1.1 christos starting_p = p; p++; /* skip '%' */ 678 1.1 christos /* parse flags */ 679 1.1 christos while (*p == '0' || *p == '-' || *p == '+' || 680 1.1 christos *p == ' ' || *p == '#' || *p == '\'') { 681 1.1 christos switch (*p) { 682 1.1 christos case '0': zero_padding = 1; break; 683 1.1 christos case '-': justify_left = 1; break; 684 1.1 christos case '+': force_sign = 1; space_for_positive = 0; break; 685 1.1 christos case ' ': force_sign = 1; 686 1.1 christos /* If both the ' ' and '+' flags appear, the ' ' flag should be ignored */ 687 1.1 christos #ifdef PERL_COMPATIBLE 688 1.1 christos /* ... but in Perl the last of ' ' and '+' applies */ 689 1.1 christos space_for_positive = 1; 690 1.1 christos #endif 691 1.1 christos break; 692 1.1 christos case '#': alternate_form = 1; break; 693 1.1 christos case '\'': break; 694 1.1 christos } 695 1.1 christos p++; 696 1.1 christos } 697 1.1 christos /* If flags '0' and '-' both appear, the '0' flag should be ignored. */ 698 1.1 christos 699 1.1 christos /* parse field width */ 700 1.1 christos if (*p == '*') { 701 1.1 christos const int j = va_arg(ap, int); 702 1.1 christos p++; 703 1.1 christos if (j >= 0) min_field_width = j; 704 1.1 christos else { min_field_width = -j; justify_left = 1; } 705 1.1 christos } else if (isdigit((int)(*p))) { 706 1.1 christos atosizet(p, &p, &min_field_width); 707 1.1 christos } 708 1.1 christos /* parse precision */ 709 1.1 christos if (*p == '.') { 710 1.1 christos p++; precision_specified = 1; 711 1.1 christos if (*p == '*') { 712 1.1 christos const int j = va_arg(ap, int); 713 1.1 christos p++; 714 1.1 christos if (j >= 0) precision = j; 715 1.1 christos else { 716 1.1 christos precision_specified = 0; precision = 0; 717 1.1 christos /* NOTE: 718 1.1 christos * Solaris 2.6 man page claims that in this case the precision 719 1.1 christos * should be set to 0. Digital Unix 4.0, HPUX 10 and BSD man page 720 1.1 christos * claim that this case should be treated as unspecified precision, 721 1.1 christos * which is what we do here. 722 1.1 christos */ 723 1.1 christos } 724 1.1 christos } else if (isdigit((int)(*p))) { 725 1.1 christos atosizet(p, &p, &precision); 726 1.1 christos } 727 1.1 christos } 728 1.1 christos /* parse 'h', 'l' and 'll' length modifiers */ 729 1.1 christos if (*p == 'h' || *p == 'l') { 730 1.1 christos length_modifier = *p; p++; 731 1.1 christos if (length_modifier == 'l' && *p == 'l') { /* double el = long long */ 732 1.1 christos #ifdef SNPRINTF_LONGLONG_SUPPORT 733 1.1 christos length_modifier = '2'; /* double letter el encoded as '2' */ 734 1.1 christos #else 735 1.1 christos length_modifier = 'l'; /* treat it as a single 'l' (letter el) */ 736 1.1 christos #endif 737 1.1 christos p++; 738 1.1 christos } 739 1.1 christos } 740 1.1 christos fmt_spec = *p; 741 1.1 christos /* common synonyms: */ 742 1.1 christos switch (fmt_spec) { 743 1.1 christos case 'i': fmt_spec = 'd'; break; 744 1.1 christos case 'D': fmt_spec = 'd'; length_modifier = 'l'; break; 745 1.1 christos case 'U': fmt_spec = 'u'; length_modifier = 'l'; break; 746 1.1 christos case 'O': fmt_spec = 'o'; length_modifier = 'l'; break; 747 1.1 christos default: break; 748 1.1 christos } 749 1.1 christos /* get parameter value, do initial processing */ 750 1.1 christos switch (fmt_spec) { 751 1.1 christos case '%': /* % behaves similar to 's' regarding flags and field widths */ 752 1.1 christos case 'c': /* c behaves similar to 's' regarding flags and field widths */ 753 1.1 christos case 's': 754 1.1 christos length_modifier = '\0'; /* wint_t and wchar_t not supported */ 755 1.1 christos /* the result of zero padding flag with non-numeric conversion specifier*/ 756 1.1 christos /* is undefined. Solaris and HPUX 10 does zero padding in this case, */ 757 1.1 christos /* Digital Unix and Linux does not. */ 758 1.1 christos #if !defined(SOLARIS_COMPATIBLE) && !defined(HPUX_COMPATIBLE) 759 1.1 christos zero_padding = 0; /* turn zero padding off for string conversions */ 760 1.1 christos #endif 761 1.1 christos str_arg_l = 1; 762 1.1 christos switch (fmt_spec) { 763 1.1 christos case '%': 764 1.1 christos str_arg = p; break; 765 1.1 christos case 'c': { 766 1.1 christos const int j = va_arg(ap, int); 767 1.1 christos uchar_arg = (unsigned char) j; /* standard demands unsigned char */ 768 1.1 christos str_arg = (const char *) &uchar_arg; 769 1.1 christos break; 770 1.1 christos } 771 1.1 christos case 's': 772 1.1 christos str_arg = va_arg(ap, const char *); 773 1.1 christos if (!str_arg) str_arg_l = 0; 774 1.1 christos /* make sure not to address string beyond the specified precision !!! */ 775 1.1 christos else if (!precision_specified) str_arg_l = strlen(str_arg); 776 1.1 christos /* truncate string if necessary as requested by precision */ 777 1.1 christos else if (precision == 0) str_arg_l = 0; 778 1.1 christos else { 779 1.1 christos /* memchr on HP does not like n > 2^31 !!! */ 780 1.1 christos const char *const q = (const char *) memchr(str_arg, '\0', 781 1.1 christos precision <= 0x7fffffff ? precision : 0x7fffffff); 782 1.1 christos str_arg_l = !q ? precision : (q-str_arg); 783 1.1 christos } 784 1.1 christos break; 785 1.1 christos default: break; 786 1.1 christos } 787 1.1 christos break; 788 1.1 christos case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': { 789 1.1 christos /* NOTE: the u, o, x, X and p conversion specifiers imply 790 1.1 christos the value is unsigned; d implies a signed value */ 791 1.1 christos 792 1.1 christos int arg_sign = 0; 793 1.1 christos /* 0 if numeric argument is zero (or if pointer is NULL for 'p'), 794 1.1 christos +1 if greater than zero (or nonzero for unsigned arguments), 795 1.1 christos -1 if negative (unsigned argument is never negative) */ 796 1.1 christos 797 1.1 christos int int_arg = 0; unsigned int uint_arg = 0; 798 1.1 christos /* only defined for length modifier h, or for no length modifiers */ 799 1.1 christos 800 1.1 christos long int long_arg = 0; unsigned long int ulong_arg = 0; 801 1.1 christos /* only defined for length modifier l (letter el) */ 802 1.1 christos 803 1.1 christos void *ptr_arg = NULL; 804 1.1 christos /* pointer argument value - only defined for p conversion */ 805 1.1 christos 806 1.1 christos #ifdef SNPRINTF_LONGLONG_SUPPORT 807 1.1 christos long long int long_long_arg = 0; 808 1.1 christos unsigned long long int ulong_long_arg = 0; 809 1.1 christos /* only defined for length modifier ll (double letter el) */ 810 1.1 christos #endif 811 1.1 christos if (fmt_spec == 'p') { 812 1.1 christos /* HPUX 10: An l, h, ll or L before any other conversion character 813 1.1 christos * (other than d, i, u, o, x, or X) is ignored. 814 1.1 christos * Digital Unix: 815 1.1 christos * not specified, but seems to behave as HPUX does. 816 1.1 christos * Solaris: If an h, l, or L appears before any other conversion 817 1.1 christos * specifier (other than d, i, u, o, x, or X), the behavior 818 1.1 christos * is undefined. (Actually %hp converts only 16-bits of address 819 1.1 christos * and %llp treats address as 64-bit data which is incompatible 820 1.1 christos * with (void *) argument on a 32-bit system). 821 1.1 christos */ 822 1.1 christos #ifdef SOLARIS_COMPATIBLE 823 1.1 christos # ifdef SOLARIS_BUG_COMPATIBLE 824 1.1 christos /* keep length modifiers even if it represents 'll' */ 825 1.1 christos # else 826 1.1 christos if (length_modifier == '2') length_modifier = '\0'; 827 1.1 christos # endif 828 1.1 christos #else 829 1.1 christos length_modifier = '\0'; 830 1.1 christos #endif 831 1.1 christos ptr_arg = va_arg(ap, void *); 832 1.1 christos if (ptr_arg != NULL) arg_sign = 1; 833 1.1 christos } else if (fmt_spec == 'd') { /* signed */ 834 1.1 christos switch (length_modifier) { 835 1.1 christos case '\0': 836 1.1 christos case 'h': 837 1.1 christos /* It is non-portable to specify char or short as the second argument 838 1.1 christos * to va_arg, because arguments seen by the called function 839 1.1 christos * are not char or short. C converts char and short arguments 840 1.1 christos * to int before passing them to a function. 841 1.1 christos */ 842 1.1 christos int_arg = va_arg(ap, int); 843 1.1 christos if (int_arg > 0) arg_sign = 1; 844 1.1 christos else if (int_arg < 0) arg_sign = -1; 845 1.1 christos break; 846 1.1 christos case 'l': /* letter el */ 847 1.1 christos long_arg = va_arg(ap, long int); 848 1.1 christos if (long_arg > 0) arg_sign = 1; 849 1.1 christos else if (long_arg < 0) arg_sign = -1; 850 1.1 christos break; 851 1.1 christos #ifdef SNPRINTF_LONGLONG_SUPPORT 852 1.1 christos case '2': 853 1.1 christos long_long_arg = va_arg(ap, long long int); 854 1.1 christos if (long_long_arg > 0) arg_sign = 1; 855 1.1 christos else if (long_long_arg < 0) arg_sign = -1; 856 1.1 christos break; 857 1.1 christos #endif 858 1.1 christos } 859 1.1 christos } else { /* unsigned */ 860 1.1 christos switch (length_modifier) { 861 1.1 christos case '\0': 862 1.1 christos case 'h': 863 1.1 christos uint_arg = va_arg(ap, unsigned int); 864 1.1 christos if (uint_arg) arg_sign = 1; 865 1.1 christos break; 866 1.1 christos case 'l': /* letter el */ 867 1.1 christos ulong_arg = va_arg(ap, unsigned long int); 868 1.1 christos if (ulong_arg) arg_sign = 1; 869 1.1 christos break; 870 1.1 christos #ifdef SNPRINTF_LONGLONG_SUPPORT 871 1.1 christos case '2': 872 1.1 christos ulong_long_arg = va_arg(ap, unsigned long long int); 873 1.1 christos if (ulong_long_arg) arg_sign = 1; 874 1.1 christos break; 875 1.1 christos #endif 876 1.1 christos } 877 1.1 christos } 878 1.1 christos str_arg = tmp; str_arg_l = 0; 879 1.1 christos /* NOTE: 880 1.1 christos * For d, i, u, o, x, and X conversions, if precision is specified, 881 1.1 christos * the '0' flag should be ignored. This is so with Solaris 2.6, 882 1.1 christos * Digital UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl. 883 1.1 christos */ 884 1.1 christos #ifndef PERL_COMPATIBLE 885 1.1 christos if (precision_specified) zero_padding = 0; 886 1.1 christos #endif 887 1.1 christos if (fmt_spec == 'd') { 888 1.1 christos if (force_sign && arg_sign >= 0) 889 1.1 christos tmp[str_arg_l++] = space_for_positive ? ' ' : '+'; 890 1.1 christos /* leave negative numbers for sprintf to handle, 891 1.1 christos to avoid handling tricky cases like (short int)(-32768) */ 892 1.1 christos #ifdef LINUX_COMPATIBLE 893 1.1 christos } else if (fmt_spec == 'p' && force_sign && arg_sign > 0) { 894 1.1 christos tmp[str_arg_l++] = space_for_positive ? ' ' : '+'; 895 1.1 christos #endif 896 1.1 christos } else if (alternate_form) { 897 1.1 christos if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X') ) 898 1.1 christos { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = fmt_spec; } 899 1.1 christos /* alternate form should have no effect for p conversion, but ... */ 900 1.1 christos #ifdef HPUX_COMPATIBLE 901 1.1 christos else if (fmt_spec == 'p' 902 1.1 christos /* HPUX 10: for an alternate form of p conversion, 903 1.1 christos * a nonzero result is prefixed by 0x. */ 904 1.1 christos #ifndef HPUX_BUG_COMPATIBLE 905 1.1 christos /* Actually it uses 0x prefix even for a zero value. */ 906 1.1 christos && arg_sign != 0 907 1.1 christos #endif 908 1.1 christos ) { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = 'x'; } 909 1.1 christos #endif 910 1.1 christos } 911 1.1 christos zero_padding_insertion_ind = str_arg_l; 912 1.1 christos if (!precision_specified) precision = 1; /* default precision is 1 */ 913 1.1 christos if (precision == 0 && arg_sign == 0 914 1.1 christos #if defined(HPUX_BUG_COMPATIBLE) || defined(LINUX_COMPATIBLE) 915 1.1 christos && fmt_spec != 'p' 916 1.1 christos /* HPUX 10 man page claims: With conversion character p the result of 917 1.1 christos * converting a zero value with a precision of zero is a null string. 918 1.1 christos * Actually HP returns all zeroes, and Linux returns "(nil)". */ 919 1.1 christos #endif 920 1.1 christos ) { 921 1.1 christos /* converted to null string */ 922 1.1 christos /* When zero value is formatted with an explicit precision 0, 923 1.1 christos the resulting formatted string is empty (d, i, u, o, x, X, p). */ 924 1.1 christos } else { 925 1.1 christos static int sprintf_return_value_is_ansi_compliant = -1; /* unknown */ 926 1.1 christos char f[5]; int f_l = 0, sprintf_l = 0; 927 1.1 christos f[f_l++] = '%'; /* construct a simple format string for sprintf */ 928 1.1 christos if (!length_modifier) { } 929 1.1 christos else if (length_modifier=='2') { f[f_l++] = 'l'; f[f_l++] = 'l'; } 930 1.1 christos else f[f_l++] = length_modifier; 931 1.1 christos f[f_l++] = fmt_spec; f[f_l++] = '\0'; 932 1.1 christos if (sprintf_return_value_is_ansi_compliant < 0) { /* not yet known */ 933 1.1 christos /* let's do a little run-time experiment (only once) to see if the 934 1.1 christos * native sprintf returns a string length as required by ANSI, or has 935 1.1 christos * some other ideas like the old SunOS which returns buffer address */ 936 1.1 christos sprintf_return_value_is_ansi_compliant = 937 1.1 christos (sprintf(tmp+str_arg_l, "%d", 19) == 2); 938 1.1 christos } 939 1.1 christos if (fmt_spec == 'p') sprintf_l=sprintf(tmp+str_arg_l, f, ptr_arg); 940 1.1 christos else if (fmt_spec == 'd') { /* signed */ 941 1.1 christos switch (length_modifier) { 942 1.1 christos case '\0': 943 1.1 christos case 'h': sprintf_l=sprintf(tmp+str_arg_l, f, int_arg); break; 944 1.1 christos case 'l': sprintf_l=sprintf(tmp+str_arg_l, f, long_arg); break; 945 1.1 christos #ifdef SNPRINTF_LONGLONG_SUPPORT 946 1.1 christos case '2': sprintf_l=sprintf(tmp+str_arg_l,f,long_long_arg); break; 947 1.1 christos #endif 948 1.1 christos } 949 1.1 christos } else { /* unsigned */ 950 1.1 christos switch (length_modifier) { 951 1.1 christos case '\0': 952 1.1 christos case 'h': sprintf_l=sprintf(tmp+str_arg_l, f, uint_arg); break; 953 1.1 christos case 'l': sprintf_l=sprintf(tmp+str_arg_l, f, ulong_arg); break; 954 1.1 christos #ifdef SNPRINTF_LONGLONG_SUPPORT 955 1.1 christos case '2': sprintf_l=sprintf(tmp+str_arg_l,f,ulong_long_arg);break; 956 1.1 christos #endif 957 1.1 christos } 958 1.1 christos } 959 1.1 christos if (!sprintf_return_value_is_ansi_compliant) { /* broken sprintf? */ 960 1.1 christos tmp[sizeof(tmp)-1] = '\0'; sprintf_l = strlen(tmp+str_arg_l); 961 1.1 christos } 962 1.1 christos assert(sprintf_l >= 0); /* should not happen; problem in sprintf? */ 963 1.1 christos assert(sprintf_l+str_arg_l < sizeof(tmp)); /*better late then never*/ 964 1.1 christos str_arg_l += sprintf_l; 965 1.1 christos /* include the optional minus sign and possible "0x" 966 1.1 christos in the region before the zero padding insertion point */ 967 1.1 christos if (zero_padding_insertion_ind < str_arg_l && 968 1.1 christos tmp[zero_padding_insertion_ind] == '-') { 969 1.1 christos zero_padding_insertion_ind++; 970 1.1 christos } 971 1.1 christos if (zero_padding_insertion_ind+1 < str_arg_l && 972 1.1 christos tmp[zero_padding_insertion_ind] == '0' && 973 1.1 christos (tmp[zero_padding_insertion_ind+1] == 'x' || 974 1.1 christos tmp[zero_padding_insertion_ind+1] == 'X') ) { 975 1.1 christos zero_padding_insertion_ind += 2; 976 1.1 christos } 977 1.1 christos } 978 1.1 christos { const size_t num_of_digits = str_arg_l - zero_padding_insertion_ind; 979 1.1 christos if (alternate_form && fmt_spec == 'o' 980 1.1 christos #ifdef HPUX_COMPATIBLE /* ("%#.o",0) -> "" */ 981 1.1 christos && (str_arg_l > 0) 982 1.1 christos #endif 983 1.1 christos #ifdef DIGITAL_UNIX_BUG_COMPATIBLE /* ("%#o",0) -> "00" */ 984 1.1 christos #else 985 1.1 christos /* unless zero is already the first character */ 986 1.1 christos && !(zero_padding_insertion_ind < str_arg_l 987 1.1 christos && tmp[zero_padding_insertion_ind] == '0') 988 1.1 christos #endif 989 1.1 christos ) { /* assure leading zero for alternate-form octal numbers */ 990 1.1 christos if (!precision_specified || precision < num_of_digits+1) { 991 1.1 christos /* precision is increased to force the first character to be zero, 992 1.1 christos except if a zero value is formatted with an explicit precision 993 1.1 christos of zero */ 994 1.1 christos precision = num_of_digits+1; precision_specified = 1; 995 1.1 christos } 996 1.1 christos } 997 1.1 christos /* zero padding to specified precision? */ 998 1.1 christos if (num_of_digits < precision) 999 1.1 christos number_of_zeros_to_pad = precision - num_of_digits; 1000 1.1 christos } 1001 1.1 christos /* zero padding to specified minimal field width? */ 1002 1.1 christos if (!justify_left && zero_padding) { 1003 1.1 christos const int n = min_field_width - (str_arg_l+number_of_zeros_to_pad); 1004 1.1 christos if (n > 0) number_of_zeros_to_pad += n; 1005 1.1 christos } 1006 1.1 christos break; 1007 1.1 christos } 1008 1.1 christos case 'n': { 1009 1.1 christos void *const ptr = va_arg(ap, void *); 1010 1.1 christos if (ptr != NULL) { 1011 1.1 christos /* same problem of size_t -> int type conversion as with the 1012 1.1 christos * snprintf return value - see comment at the end of this procedure */ 1013 1.1 christos switch (length_modifier) { 1014 1.1 christos case '\0': *( int *const)ptr = str_l; break; 1015 1.1 christos case 'h': *(short int *const)ptr = str_l; break; 1016 1.1 christos case 'l': *(long int *const)ptr = str_l; break; 1017 1.1 christos #ifdef SNPRINTF_LONGLONG_SUPPORT 1018 1.1 christos case '2': *(long long int *const)ptr = str_l; break; 1019 1.1 christos #endif 1020 1.1 christos } 1021 1.1 christos } 1022 1.1 christos /* no argument converted */ 1023 1.1 christos min_field_width = number_of_zeros_to_pad = str_arg_l = 0; 1024 1.1 christos break; 1025 1.1 christos } 1026 1.1 christos default: /* unrecognized conversion specifier, keep format string as-is*/ 1027 1.1 christos zero_padding = 0; /* turn zero padding off for non-numeric convers. */ 1028 1.1 christos #ifndef DIGITAL_UNIX_COMPATIBLE 1029 1.1 christos justify_left = 1; min_field_width = 0; /* reset flags */ 1030 1.1 christos #endif 1031 1.1 christos #if defined(PERL_COMPATIBLE) || defined(LINUX_COMPATIBLE) 1032 1.1 christos /* keep the entire format string unchanged */ 1033 1.1 christos str_arg = starting_p; str_arg_l = p - starting_p; 1034 1.1 christos /* well, not exactly so for Linux, which does something inbetween, 1035 1.1 christos * and I don't feel an urge to imitate it: "%+++++hy" -> "%+y" */ 1036 1.1 christos #else 1037 1.1 christos /* discard the unrecognized conversion, just keep * 1038 1.1 christos * the unrecognized conversion character */ 1039 1.1 christos str_arg = p; str_arg_l = 0; 1040 1.1 christos #endif 1041 1.1 christos if (*p) str_arg_l++; /* include invalid conversion specifier unchanged 1042 1.1 christos if not at end-of-string */ 1043 1.1 christos break; 1044 1.1 christos } 1045 1.1 christos if (*p) p++; /* step over the just processed conversion specifier */ 1046 1.1 christos /* insert padding to the left as requested by min_field_width; 1047 1.1 christos this does not include the zero padding in case of numerical conversions*/ 1048 1.1 christos if (!justify_left) { /* left padding with blank or zero */ 1049 1.1 christos const int n = min_field_width - (str_arg_l+number_of_zeros_to_pad); 1050 1.1 christos if (n > 0) { 1051 1.1 christos if (str_l < str_m) { 1052 1.1 christos const size_t avail = str_m-str_l; 1053 1.1 christos fast_memset(str+str_l, (zero_padding?'0':' '), 1054 1.1 christos ((unsigned int)n > avail ? avail : (unsigned int)n)); 1055 1.1 christos } 1056 1.1 christos str_l += n; 1057 1.1 christos } 1058 1.1 christos } 1059 1.1 christos /* is zero padding as requested by the precision or by the 1060 1.1 christos * minimal field width for numeric conversions required? */ 1061 1.1 christos if (number_of_zeros_to_pad <= 0) { 1062 1.1 christos /* will not copy the first part of numeric right now, * 1063 1.1 christos * force it to be copied later in its entirety */ 1064 1.1 christos zero_padding_insertion_ind = 0; 1065 1.1 christos } else { 1066 1.1 christos /* insert first part of numerics (sign or '0x') before zero padding */ 1067 1.1 christos { const int n = zero_padding_insertion_ind; 1068 1.1 christos if (n > 0) { 1069 1.1 christos if (str_l < str_m) { 1070 1.1 christos const size_t avail = str_m-str_l; 1071 1.1 christos fast_memcpy(str+str_l, str_arg, 1072 1.1 christos ((unsigned int)n > avail ? avail : (unsigned int)n)); 1073 1.1 christos } 1074 1.1 christos str_l += n; 1075 1.1 christos } 1076 1.1 christos } 1077 1.1 christos /* insert zero padding as requested by the precision or min field width */ 1078 1.1 christos { const int n = number_of_zeros_to_pad; 1079 1.1 christos if (n > 0) { 1080 1.1 christos if (str_l < str_m) { 1081 1.1 christos const size_t avail = str_m-str_l; 1082 1.1 christos fast_memset(str+str_l, '0', 1083 1.1 christos ((unsigned int)n > avail ? avail : (unsigned int)n)); 1084 1.1 christos } 1085 1.1 christos str_l += n; 1086 1.1 christos } 1087 1.1 christos } 1088 1.1 christos } 1089 1.1 christos /* insert formatted string 1090 1.1 christos * (or as-is conversion specifier for unknown conversions) */ 1091 1.1 christos { const int n = str_arg_l - zero_padding_insertion_ind; 1092 1.1 christos if (n > 0) { 1093 1.1 christos if (str_l < str_m) { 1094 1.1 christos const size_t avail = str_m-str_l; 1095 1.1 christos fast_memcpy(str+str_l, str_arg+zero_padding_insertion_ind, 1096 1.1 christos ((unsigned int)n > avail ? avail : (unsigned int)n)); 1097 1.1 christos } 1098 1.1 christos str_l += n; 1099 1.1 christos } 1100 1.1 christos } 1101 1.1 christos /* insert right padding */ 1102 1.1 christos if (justify_left) { /* right blank padding to the field width */ 1103 1.1 christos const int n = min_field_width - (str_arg_l+number_of_zeros_to_pad); 1104 1.1 christos if (n > 0) { 1105 1.1 christos if (str_l < str_m) { 1106 1.1 christos const size_t avail = str_m-str_l; 1107 1.1 christos fast_memset(str+str_l, ' ', 1108 1.1 christos ((unsigned int)n > avail ? avail : (unsigned int)n)); 1109 1.1 christos } 1110 1.1 christos str_l += n; 1111 1.1 christos } 1112 1.1 christos } 1113 1.1 christos } 1114 1.1 christos } 1115 1.1 christos #if defined(NEED_SNPRINTF_ONLY) 1116 1.1 christos va_end(ap); 1117 1.1 christos #endif 1118 1.1 christos if (str_m > 0) { /* make sure the string is null-terminated, possibly 1119 1.1 christos at the expense of overwriting the last character */ 1120 1.1 christos str[str_l <= str_m-1 ? str_l : str_m-1] = '\0'; 1121 1.1 christos } 1122 1.1 christos /* Return the number of characters formatted (excluding trailing null 1123 1.1 christos * character), that is, the number of characters that would have been 1124 1.1 christos * written to the buffer if it were large enough. 1125 1.1 christos * 1126 1.1 christos * The value of str_l should be returned, but str_l is of unsigned type 1127 1.1 christos * size_t, and snprintf is int, possibly leading to an undetected 1128 1.1 christos * integer overflow, resulting in a negative return value, which is invalid. 1129 1.1 christos * Both XSH5 and ISO C99 (at least the draft) are silent on this issue. 1130 1.1 christos * Should errno be set to EOVERFLOW and EOF returned in this case??? 1131 1.1 christos */ 1132 1.1 christos return (int) str_l; 1133 1.1 christos } 1134 #endif 1135