1 /* Copyright (c) 2005-2010, 2012-2015. The SimGrid Team.
2 * All rights reserved. */
4 /* This program is free software; you can redistribute it and/or modify it
5 * under the terms of the license (GNU LGPL) which comes with this package. */
8 * snprintf.c - a portable implementation of snprintf
11 * Mark Martinec <mark.martinec@ijs.si>, April 1999.
13 * Copyright 1999, Mark Martinec. All rights reserved.
15 * TERMS AND CONDITIONS
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the "Frontier Artistic License" which comes
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty
22 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23 * See the Frontier Artistic License for more details.
25 * You should have received a copy of the Frontier Artistic License
26 * with this Kit in the file named LICENSE.txt .
27 * If not, I'll be glad to provide one.
30 * - careful adherence to specs regarding flags, field width and precision;
31 * - good performance for large string handling (large format, large
32 * argument or large paddings). Performance is similar to system's sprintf
33 * and in several cases significantly better (make sure you compile with
34 * optimizations turned on, tell the compiler the code is strict ANSI
35 * if necessary to give it more freedom for optimizations);
36 * - return value semantics per ISO/IEC 9899:1999 ("ISO C99");
37 * - written in standard ISO/ANSI C - requires an ANSI C compiler.
39 * SUPPORTED CONVERSION SPECIFIERS AND DATA TYPES
41 * This snprintf only supports the following conversion specifiers:
42 * s, c, d, u, o, x, X, p (and synonyms: i, D, U, O - see below)
43 * with flags: '-', '+', ' ', '0' and '#'.
44 * An asterisk is supported for field width as well as precision.
46 * Length modifiers 'h' (short int), 'l' (long int),
47 * and 'll' (long long int) are supported.
49 * If macro SNPRINTF_LONGLONG_SUPPORT is not defined (default) the
50 * length modifier 'll' is recognized but treated the same as 'l',
51 * which may cause argument value truncation! Defining
52 * SNPRINTF_LONGLONG_SUPPORT requires that your system's sprintf also
53 * handles length modifier 'll'. long long int is a language extension
54 * which may not be portable.
56 * Conversion of numeric data (conversion specifiers d, u, o, x, X, p)
57 * with length modifiers (none or h, l, ll) is left to the system routine
58 * sprintf, but all handling of flags, field width and precision as well as
59 * c and s conversions is done very carefully by this portable routine.
60 * If a string precision (truncation) is specified (e.g. %.8s) it is
61 * guaranteed the string beyond the specified precision will not be referenced.
63 * Length modifiers h, l and ll are ignored for c and s conversions (data
64 * types wint_t and wchar_t are not supported).
66 * The following common synonyms for conversion characters are supported:
67 * - i is a synonym for d
68 * - D is a synonym for ld, explicit length modifiers are ignored
69 * - U is a synonym for lu, explicit length modifiers are ignored
70 * - O is a synonym for lo, explicit length modifiers are ignored
71 * The D, O and U conversion characters are nonstandard, they are supported
72 * for backward compatibility only, and should not be used for new code.
74 * The following is specifically NOT supported:
75 * - flag ' (thousands' grouping character) is recognized but ignored
76 * - numeric conversion specifiers: f, e, E, g, G and synonym F,
77 * as well as the new a and A conversion specifiers
78 * - length modifier 'L' (long double) and 'q' (quad - use 'll' instead)
79 * - wide character/string conversions: lc, ls, and nonstandard
81 * - writeback of converted string length: conversion character n
82 * - the n$ specification for direct reference to n-th argument
85 * It is permitted for str_m to be zero, and it is permitted to specify NULL
86 * pointer for resulting string argument if str_m is zero (as per ISO C99).
88 * The return value is the number of characters which would be generated
89 * for the given input, excluding the trailing null. If this value
90 * is greater or equal to str_m, not all characters from the result
91 * have been stored in str, output bytes beyond the (str_m-1) -th character
92 * are discarded. If str_m is greater than zero it is guaranteed
93 * the resulting string will be null-terminated.
95 * NOTE that this matches the ISO C99, OpenBSD, and GNU C library 2.1,
96 * but is different from some older and vendor implementations,
97 * and is also different from XPG, XSH5, SUSv2 specifications.
98 * For historical discussion on changes in the semantics and standards
99 * of snprintf see printf(3) man page in the Linux programmers manual.
101 * Routines asprintf and vasprintf return a pointer (in the ptr argument)
102 * to a buffer sufficiently large to hold the resulting string. This pointer
103 * should be passed to free(3) to release the allocated storage when it is
104 * no longer needed. If sufficient space cannot be allocated, these functions
105 * will return -1 and set ptr to be a NULL pointer. These two routines are a
106 * GNU C library extensions (glibc).
108 * Routines asnprintf and vasnprintf are similar to asprintf and vasprintf,
109 * yet, like snprintf and vsnprintf counterparts, will write at most str_m-1
110 * characters into the allocated output string, the last character in the
111 * allocated buffer then gets the terminating null. If the formatted string
112 * length (the return value) is greater than or equal to the str_m argument,
113 * the resulting string was truncated and some of the formatted characters
114 * were discarded. These routines present a handy way to limit the amount
115 * of allocated memory to some sane value.
118 * http://www.ijs.si/software/snprintf/
121 * 1999-04 V0.9 Mark Martinec
122 * - initial version, some modifications after comparing printf
123 * man pages for Digital Unix 4.0, Solaris 2.6 and HPUX 10,
124 * and checking how Perl handles sprintf (differently!);
125 * 1999-04-09 V1.0 Mark Martinec <mark.martinec@ijs.si>
126 * - added main test program, fixed remaining inconsistencies,
127 * added optional (long long int) support;
128 * 1999-04-12 V1.1 Mark Martinec <mark.martinec@ijs.si>
129 * - support the 'p' conversion (pointer to void);
130 * - if a string precision is specified
131 * make sure the string beyond the specified precision
132 * will not be referenced (e.g. by strlen);
133 * 1999-04-13 V1.2 Mark Martinec <mark.martinec@ijs.si>
134 * - support synonyms %D=%ld, %U=%lu, %O=%lo;
135 * - speed up the case of long format string with few conversions;
136 * 1999-06-30 V1.3 Mark Martinec <mark.martinec@ijs.si>
137 * - fixed runaway loop (eventually crashing when str_l wraps
138 * beyond 2^31) while copying format string without
139 * conversion specifiers to a buffer that is too short
140 * (thanks to Edwin Young <edwiny@autonomy.com> for
141 * spotting the problem);
142 * - added macros PORTABLE_SNPRINTF_VERSION_(MAJOR|MINOR)
144 * 2000-02-14 V2.0 (never released) Mark Martinec <mark.martinec@ijs.si>
145 * - relaxed license terms: The Artistic License now applies.
146 * You may still apply the GNU GENERAL PUBLIC LICENSE
147 * as was distributed with previous versions, if you prefer;
148 * - changed REVISION HISTORY dates to use ISO 8601 date format;
149 * - added vsnprintf (patch also independently proposed by
150 * Caolan McNamara 2000-05-04, and Keith M Willenson 2000-06-01)
151 * 2000-06-27 V2.1 Mark Martinec <mark.martinec@ijs.si>
152 * - removed POSIX check for str_m<1; value 0 for str_m is
153 * allowed by ISO C99 (and GNU C library 2.1) - (pointed out
154 * on 2000-05-04 by Caolan McNamara, caolan@ csn dot ul dot ie).
155 * Besides relaxed license this change in standards adherence
156 * is the main reason to bump up the major version number;
157 * - added nonstandard routines asnprintf, vasnprintf, asprintf,
158 * vasprintf that dynamically allocate storage for the
159 * resulting string; these routines are not compiled by default,
160 * see comments where NEED_V?ASN?PRINTF macros are defined;
161 * - autoconf contributed by Caolan McNamara
162 * 2000-10-06 V2.2 Mark Martinec <mark.martinec@ijs.si>
163 * - BUG FIX: the %c conversion used a temporary variable
164 * that was no longer in scope when referenced,
165 * possibly causing incorrect resulting character;
166 * - BUG FIX: make precision and minimal field width unsigned
167 * to handle huge values (2^31 <= n < 2^32) correctly;
168 * also be more careful in the use of signed/unsigned/size_t
169 * internal variables - probably more careful than many
170 * vendor implementations, but there may still be a case
171 * where huge values of str_m, precision or minimal field
172 * could cause incorrect behaviour;
173 * - use separate variables for signed/unsigned arguments,
174 * and for short/int, long, and long long argument lengths
175 * to avoid possible incompatibilities on certain
176 * computer architectures. Also use separate variable
177 * arg_sign to hold sign of a numeric argument,
178 * to make code more transparent;
179 * - some fiddling with zero padding and "0x" to make it
181 * - systematically use macros fast_memcpy and fast_memset
182 * instead of case-by-case hand optimization; determine some
183 * breakeven string lengths for different architectures;
184 * - terminology change: 'format' -> 'conversion specifier',
185 * 'C9x' -> 'ISO/IEC 9899:1999 ("ISO C99")',
186 * 'alternative form' -> 'alternate form',
187 * 'data type modifier' -> 'length modifier';
188 * - several comments rephrased and new ones added;
189 * - make compiler not complain about 'credits' defined but
193 /* Define NEED_V?ASN?PRINTF macros if you need library extension
194 * routines asprintf, vasprintf, asnprintf, vasnprintf respectively,
195 * and your system library does not provide them. They are all small
196 * wrapper routines around portable_vsnprintf. Defining any of the four
197 * NEED_V?ASN?PRINTF macros automatically turns off NEED_SNPRINTF_ONLY
198 * and turns on PREFER_PORTABLE_SNPRINTF.
200 * Watch for name conflicts with the system library if these routines
201 * are already present there.
203 * NOTE: vasprintf and vasnprintf routines need va_copy() from stdarg.h, as
204 * specified by C99, to be able to traverse the same list of arguments twice.
205 * I don't know of any other standard and portable way of achieving the same.
206 * With some versions of gcc you may use __va_copy(). You might even get away
207 * with "ap2 = ap", in this case you must not call va_end(ap2) !
208 * #define va_copy(ap2,ap) ap2 = ap
210 /* #define NEED_ASPRINTF */
211 /* #define NEED_ASNPRINTF */
212 /* #define NEED_VASPRINTF */
213 /* #define NEED_VASNPRINTF */
216 /* ============================================= */
217 /* NO USER SERVICABLE PARTS FOLLOWING THIS POINT */
218 /* ============================================= */
220 #include "src/portable.h" /* to get a working stdarg.h */
222 #include <sys/types.h>
232 #if defined(NEED_ASPRINTF)
233 int asprintf(char **ptr, const char *fmt, /*args */ ...);
235 #if defined(NEED_VASPRINTF)
236 int vasprintf(char **ptr, const char *fmt, va_list ap);
240 /* FIXME: better place */
241 #include "xbt/sysdep.h"
247 snprintf.c, v2.2: Mark Martinec, <mark.martinec@ijs.si>
248 snprintf.c, v2.2: Copyright 1999, Mark Martinec. Frontier Artistic License applies.
249 snprintf.c, v2.2: http://www.ijs.si/software/snprintf
252 #if defined(NEED_ASPRINTF)
253 int asprintf(char **ptr, const char *fmt, /*args */ ...)
260 va_start(ap, fmt); /* measure the required size */
261 str_l = portable_vsnprintf(NULL, (size_t) 0, fmt, ap);
263 assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */
264 *ptr = (char *) xbt_malloc(str_m = (size_t) str_l + 1);
271 str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
273 assert(str_l2 == str_l);
279 #if defined(NEED_VASPRINTF)
280 int vasprintf(char **ptr, const char *fmt, va_list ap)
288 va_copy(ap2, ap); /* don't consume the original ap, we'll need it again */
289 str_l = portable_vsnprintf(NULL, (size_t) 0, fmt, ap2); /*get required size */
292 assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */
293 *ptr = (char *) xbt_malloc(str_m = (size_t) str_l + 1);
298 int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
299 assert(str_l2 == str_l);
305 #if defined(NEED_ASNPRINTF)
306 int asnprintf(char **ptr, size_t str_m, const char *fmt, /*args */ ...)
312 va_start(ap, fmt); /* measure the required size */
313 str_l = portable_vsnprintf(NULL, (size_t) 0, fmt, ap);
315 assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */
316 if ((size_t) str_l + 1 < str_m)
317 str_m = (size_t) str_l + 1; /* truncate */
318 /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */
319 if (str_m == 0) { /* not interested in resulting string, just return size */
321 *ptr = (char *) xbt_malloc(str_m);
328 str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
330 assert(str_l2 == str_l);
337 #if defined(NEED_VASNPRINTF)
338 int vasnprintf(char **ptr, size_t str_m, const char *fmt, va_list ap)
345 va_copy(ap2, ap); /* don't consume the original ap, we'll need it again */
346 str_l = portable_vsnprintf(NULL, (size_t) 0, fmt, ap2); /*get required size */
349 assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */
350 if ((size_t) str_l + 1 < str_m)
351 str_m = (size_t) str_l + 1; /* truncate */
352 /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */
353 if (str_m == 0) { /* not interested in resulting string, just return size */
355 *ptr = (char *) xbt_malloc(str_m);
360 int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
361 assert(str_l2 == str_l);
370 char *bvprintf(const char *fmt, va_list ap)
374 if (vasprintf(&res, fmt, ap) < 0) {
375 /* Do not want to use xbt_die() here, as it uses the logging
376 * infrastucture and may fail to allocate memory too. */
377 fprintf(stderr, "bprintf: vasprintf failed. Aborting.\n");
383 char *bprintf(const char *fmt, ...)
389 res = bvprintf(fmt, ap);