1 /* __gmp_replacement_vsnprintf -- for systems which don't have vsnprintf, or
2 only have a broken one.
4 THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY. THEY'RE ALMOST
5 CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
6 FUTURE GNU MP RELEASES.
8 Copyright 2001, 2002 Free Software Foundation, Inc.
10 This file is part of the GNU MP Library.
12 The GNU MP Library is free software; you can redistribute it and/or modify
13 it under the terms of either:
15 * the GNU Lesser General Public License as published by the Free
16 Software Foundation; either version 3 of the License, or (at your
17 option) any later version.
21 * the GNU General Public License as published by the Free Software
22 Foundation; either version 2 of the License, or (at your option) any
25 or both in parallel, as here.
27 The GNU MP Library is distributed in the hope that it will be useful, but
28 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
29 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
32 You should have received copies of the GNU General Public License and the
33 GNU Lesser General Public License along with the GNU MP Library. If not,
34 see https://www.gnu.org/licenses/. */
38 #if ! HAVE_VSNPRINTF /* only need this file if we don't have vsnprintf */
41 #define _GNU_SOURCE /* for strnlen prototype */
44 #include <ctype.h> /* for isdigit */
45 #include <stddef.h> /* for ptrdiff_t */
47 #include <stdio.h> /* for NULL */
51 #include <float.h> /* for DBL_MAX_10_EXP etc */
55 # include <inttypes.h> /* for intmax_t */
63 #include <sys/types.h> /* for quad_t */
70 /* Autoconf notes that AIX 4.3 has a broken strnlen, but fortunately it
71 doesn't affect us since __gmp_replacement_vsnprintf is not required on
75 strnlen (const char *s
, size_t n
)
78 for (i
= 0; i
< n
; i
++)
86 /* The approach here is to parse the fmt string, and decide how much space
87 it requires, then use vsprintf into a big enough buffer. The space
88 calculated isn't an exact amount, but it's certainly no less than
91 This code was inspired by GNU libiberty/vasprintf.c but we support more
92 datatypes, when available.
94 mingw32 - doesn't have vsnprintf, it seems. Because gcc is used a full
95 set of types are available, but "long double" is just a plain IEEE
96 64-bit "double" and LDBL_MAX_EXP_10 is correspondingly defined, so we
97 avoid the big 15-bit exponent estimate. */
100 __gmp_replacement_vsnprintf (char *buf
, size_t buf_size
,
101 const char *orig_fmt
, va_list orig_ap
)
105 size_t total_width
, integer_sizeof
, floating_sizeof
, len
;
107 int width
, prec
, seen_prec
, double_digits
, long_double_digits
;
110 /* preserve orig_ap for use after size estimation */
111 va_copy (ap
, orig_ap
);
114 total_width
= strlen (fmt
) + 1; /* 1 extra for the '\0' */
116 integer_sizeof
= sizeof (long);
118 integer_sizeof
= MAX (integer_sizeof
, sizeof (long long));
121 integer_sizeof
= MAX (integer_sizeof
, sizeof (quad_t
));
124 floating_sizeof
= sizeof (double);
126 floating_sizeof
= MAX (floating_sizeof
, sizeof (long double));
129 /* IEEE double or VAX G floats have an 11 bit exponent, so the default is
130 a maximum 308 decimal digits. VAX D floats have only an 8 bit
131 exponent, but we don't bother trying to detect that directly. */
133 #ifdef DBL_MAX_10_EXP
134 /* but in any case prefer a value the compiler says */
135 double_digits
= DBL_MAX_10_EXP
;
138 /* IEEE 128-bit quad, Intel 80-bit temporary, or VAX H floats all have 15
139 bit exponents, so the default is a maximum 4932 decimal digits. */
140 long_double_digits
= 4932;
141 /* but if double == long double, then go with that size */
143 if (sizeof (double) == sizeof (long double))
144 long_double_digits
= double_digits
;
146 #ifdef LDBL_MAX_10_EXP
147 /* but in any case prefer a value the compiler says */
148 long_double_digits
= LDBL_MAX_10_EXP
;
153 fmt
= strchr (fmt
, '%');
170 /* char, already accounted for by strlen(fmt) */
179 /* at most 3 digits per byte in hex, dec or octal, plus a sign */
180 total_width
+= 3 * integer_sizeof
+ 1;
184 /* Let's assume uintmax_t is the same size as intmax_t. */
186 (void) va_arg (ap
, intmax_t);
188 ASSERT_FAIL (intmax_t not available
);
192 (void) va_arg (ap
, long);
196 (void) va_arg (ap
, long long);
198 ASSERT_FAIL (long long not available
);
202 /* quad_t is probably the same as long long, but let's treat
203 it separately just to be sure. Also let's assume u_quad_t
204 will be the same size as quad_t. */
206 (void) va_arg (ap
, quad_t
);
208 ASSERT_FAIL (quad_t
not available
);
213 (void) va_arg (ap
, ptrdiff_t);
215 ASSERT_FAIL (ptrdiff_t not available
);
219 (void) va_arg (ap
, size_t);
222 /* default is an "int", and this includes h=short and hh=char
223 since they're promoted to int in a function call */
224 (void) va_arg (ap
, int);
233 /* Requested decimals, sign, point and e, plus an overestimate
234 of exponent digits (the assumption is all the float is
236 total_width
+= prec
+ 3 + floating_sizeof
* 3;
240 (void) va_arg (ap
, long double);
242 ASSERT_FAIL (long double not available
);
246 (void) va_arg (ap
, double);
250 /* Requested decimals, sign and point, and a margin for error,
251 then add the maximum digits that can be in the integer part,
252 based on the maximum exponent value. */
253 total_width
+= prec
+ 2 + 10;
257 (void) va_arg (ap
, long double);
258 total_width
+= long_double_digits
;
260 ASSERT_FAIL (long double not available
);
265 (void) va_arg (ap
, double);
266 total_width
+= double_digits
;
270 case 'h': /* short or char */
271 case 'j': /* intmax_t */
272 case 'L': /* long long or long double */
273 case 'q': /* quad_t */
274 case 't': /* ptrdiff_t */
275 case 'z': /* size_t */
281 /* long or long long */
284 type
= 'L'; /* "ll" means "L" */
288 /* bytes written, no output as such */
289 (void) va_arg (ap
, void *);
293 /* If no precision was given, then determine the string length
294 and put it there, to be added to the total under "next". If
295 a precision was given then that's already the maximum from
296 this field, but see whether the string is shorter than that,
297 in case the limit was very big. */
299 const char *s
= va_arg (ap
, const char *);
300 prec
= (seen_prec
? strnlen (s
, prec
) : strlen (s
));
305 /* pointer, let's assume at worst it's octal with some padding */
306 (void) va_arg (ap
, const void *);
307 total_width
+= 3 * sizeof (void *) + 16;
311 /* literal %, already accounted for by strlen(fmt) */
315 /* showbase, at most 2 for "0x" */
321 /* sign, already accounted for under numerics */
325 /* left justify, no effect on total width */
335 /* negative width means left justify which can be ignored,
336 negative prec would be invalid, just use absolute value */
337 int n
= va_arg (ap
, int);
342 case '0': case '1': case '2': case '3': case '4':
343 case '5': case '6': case '7': case '8': case '9':
344 /* process all digits to form a value */
348 n
= n
* 10 + (fchar
-'0');
350 } while (isascii (fchar
) && isdigit (fchar
));
351 fmt
--; /* unget the non-digit */
357 /* incomplete or invalid % sequence */
364 total_width
+= width
;
368 if (total_width
<= buf_size
)
370 vsprintf (buf
, orig_fmt
, orig_ap
);
377 s
= __GMP_ALLOCATE_FUNC_TYPE (total_width
, char);
378 vsprintf (s
, orig_fmt
, orig_ap
);
382 size_t copylen
= MIN (len
, buf_size
-1);
383 memcpy (buf
, s
, copylen
);
386 (*__gmp_free_func
) (s
, total_width
);
389 /* If total_width was somehow wrong then chances are we've already
390 clobbered memory, but maybe this check will still work. */
391 ASSERT_ALWAYS (len
< total_width
);
396 #endif /* ! HAVE_VSNPRINTF */