Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
605231415f9ec09cc5271c8c9df949b664ab1130
[simgrid.git] / src / xbt / snprintf.c
1 /* Copyright (c) 2005-2010, 2012-2015. The SimGrid Team.
2  * All rights reserved.                                                     */
3
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. */
6
7 /*
8  * snprintf.c - a portable implementation of snprintf
9  *
10  * AUTHOR
11  *   Mark Martinec <mark.martinec@ijs.si>, April 1999.
12  *
13  *   Copyright 1999, Mark Martinec. All rights reserved.
14  *
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
18  *   with this Kit.
19  *
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.
24  *
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.
28  *
29  * FEATURES
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.
38  *
39  * SUPPORTED CONVERSION SPECIFIERS AND DATA TYPES
40  *
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.
45  *
46  * Length modifiers 'h' (short int), 'l' (long int),
47  * and 'll' (long long int) are supported.
48  * NOTE:
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.
55  *
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.
62  *
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).
65  *
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.
73  *
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
80  *     synonyms C and S
81  *   - writeback of converted string length: conversion character n
82  *   - the n$ specification for direct reference to n-th argument
83  *   - locales
84  *
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).
87  *
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.
94  *
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.
100  *
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).
107  *
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.
116  *
117  * AVAILABILITY
118  *   http://www.ijs.si/software/snprintf/
119  *
120  * REVISION HISTORY
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)
143  *      to snprintf.h
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
180  *      Linux compatible;
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
190  *      not used;
191  */
192
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.
199  *
200  * Watch for name conflicts with the system library if these routines
201  * are already present there.
202  *
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
209  */
210 /* #define NEED_ASPRINTF   */
211 /* #define NEED_ASNPRINTF  */
212 /* #define NEED_VASPRINTF  */
213 /* #define NEED_VASNPRINTF */
214
215
216 /* ============================================= */
217 /* NO USER SERVICABLE PARTS FOLLOWING THIS POINT */
218 /* ============================================= */
219
220 #include "src/portable.h"           /* to get a working stdarg.h */
221
222 #include <sys/types.h>
223 #include <string.h>
224 #include <stdlib.h>
225 #include <stdio.h>
226 #include <stdarg.h>
227
228 #include <assert.h>
229 #include <errno.h>
230 #include "xbt/str.h"
231
232 #if defined(NEED_ASPRINTF)
233 int asprintf(char **ptr, const char *fmt, /*args */ ...);
234 #endif
235 #if defined(NEED_VASPRINTF)
236 int vasprintf(char **ptr, const char *fmt, va_list ap);
237 #endif
238
239
240   /* FIXME: better place */
241 #include "xbt/sysdep.h"
242
243 /* declarations */
244
245 /*
246     Old copyright
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
250 */
251
252 #if defined(NEED_ASPRINTF)
253 int asprintf(char **ptr, const char *fmt, /*args */ ...)
254 {
255   va_list ap;
256   size_t str_m;
257   int str_l;
258
259   *ptr = NULL;
260   va_start(ap, fmt);            /* measure the required size */
261   str_l = portable_vsnprintf(NULL, (size_t) 0, fmt, ap);
262   va_end(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);
265   if (*ptr == NULL) {
266     errno = ENOMEM;
267     str_l = -1;
268   } else {
269     int str_l2;
270     va_start(ap, fmt);
271     str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
272     va_end(ap);
273     assert(str_l2 == str_l);
274   }
275   return str_l;
276 }
277 #endif
278
279 #if defined(NEED_VASPRINTF)
280 int vasprintf(char **ptr, const char *fmt, va_list ap)
281 {
282   size_t str_m;
283   int str_l;
284
285   *ptr = NULL;
286   {
287     va_list ap2;
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 */
290     va_end(ap2);
291   }
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);
294   if (*ptr == NULL) {
295     errno = ENOMEM;
296     str_l = -1;
297   } else {
298     int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
299     assert(str_l2 == str_l);
300   }
301   return str_l;
302 }
303 #endif
304
305 #if defined(NEED_ASNPRINTF)
306 int asnprintf(char **ptr, size_t str_m, const char *fmt, /*args */ ...)
307 {
308   va_list ap;
309   int str_l;
310
311   *ptr = NULL;
312   va_start(ap, fmt);            /* measure the required size */
313   str_l = portable_vsnprintf(NULL, (size_t) 0, fmt, ap);
314   va_end(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 */
320   } else {
321     *ptr = (char *) xbt_malloc(str_m);
322     if (*ptr == NULL) {
323       errno = ENOMEM;
324       str_l = -1;
325     } else {
326       int str_l2;
327       va_start(ap, fmt);
328       str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
329       va_end(ap);
330       assert(str_l2 == str_l);
331     }
332   }
333   return str_l;
334 }
335 #endif
336
337 #if defined(NEED_VASNPRINTF)
338 int vasnprintf(char **ptr, size_t str_m, const char *fmt, va_list ap)
339 {
340   int str_l;
341
342   *ptr = NULL;
343   {
344     va_list ap2;
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 */
347     va_end(ap2);
348   }
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 */
354   } else {
355     *ptr = (char *) xbt_malloc(str_m);
356     if (*ptr == NULL) {
357       errno = ENOMEM;
358       str_l = -1;
359     } else {
360       int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
361       assert(str_l2 == str_l);
362     }
363   }
364   return str_l;
365 }
366 #endif
367
368
369
370 char *bvprintf(const char *fmt, va_list ap)
371 {
372   char *res;
373
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");
378     xbt_abort();
379   }
380   return res;
381 }
382
383 char *bprintf(const char *fmt, ...)
384 {
385   va_list ap;
386   char *res;
387
388   va_start(ap, fmt);
389   res = bvprintf(fmt, ap);
390   va_end(ap);
391   return res;
392 }