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