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 the GNU Lesser General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or (at your
15 option) any later version.
17 The GNU MP Library is distributed in the hope that it will be useful, but
18 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
20 License for more details.
22 You should have received a copy of the GNU Lesser General Public License
23 along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
27 #if ! HAVE_VSNPRINTF /* only need this file if we don't have vsnprintf */
30 #define _GNU_SOURCE /* for strnlen prototype */
38 #include <ctype.h> /* for isdigit */
39 #include <stddef.h> /* for ptrdiff_t */
41 #include <stdio.h> /* for NULL */
45 #include <float.h> /* for DBL_MAX_10_EXP etc */
49 # include <inttypes.h> /* for intmax_t */
57 #include <sys/types.h> /* for quad_t */
64 /* Autoconf notes that AIX 4.3 has a broken strnlen, but fortunately it
65 doesn't affect us since __gmp_replacement_vsnprintf is not required on
69 strnlen (const char *s
, size_t n
)
72 for (i
= 0; i
< n
; i
++)
80 /* The approach here is to parse the fmt string, and decide how much space
81 it requires, then use vsprintf into a big enough buffer. The space
82 calculated isn't an exact amount, but it's certainly no less than
85 This code was inspired by GNU libiberty/vasprintf.c but we support more
86 datatypes, when available.
88 mingw32 - doesn't have vsnprintf, it seems. Because gcc is used a full
89 set of types are available, but "long double" is just a plain IEEE
90 64-bit "double" and LDBL_MAX_EXP_10 is correspondingly defined, so we
91 avoid the big 15-bit exponent estimate. */
94 __gmp_replacement_vsnprintf (char *buf
, size_t buf_size
,
95 const char *orig_fmt
, va_list orig_ap
)
99 size_t total_width
, integer_sizeof
, floating_sizeof
, len
;
101 int width
, prec
, seen_prec
, double_digits
, long_double_digits
;
104 /* preserve orig_ap for use after size estimation */
105 va_copy (ap
, orig_ap
);
108 total_width
= strlen (fmt
) + 1; /* 1 extra for the '\0' */
110 integer_sizeof
= sizeof (long);
112 integer_sizeof
= MAX (integer_sizeof
, sizeof (long long));
115 integer_sizeof
= MAX (integer_sizeof
, sizeof (quad_t
));
118 floating_sizeof
= sizeof (double);
120 floating_sizeof
= MAX (floating_sizeof
, sizeof (long double));
123 /* IEEE double or VAX G floats have an 11 bit exponent, so the default is
124 a maximum 308 decimal digits. VAX D floats have only an 8 bit
125 exponent, but we don't bother trying to detect that directly. */
127 #ifdef DBL_MAX_10_EXP
128 /* but in any case prefer a value the compiler says */
129 double_digits
= DBL_MAX_10_EXP
;
132 /* IEEE 128-bit quad, Intel 80-bit temporary, or VAX H floats all have 15
133 bit exponents, so the default is a maximum 4932 decimal digits. */
134 long_double_digits
= 4932;
135 /* but if double == long double, then go with that size */
137 if (sizeof (double) == sizeof (long double))
138 long_double_digits
= double_digits
;
140 #ifdef LDBL_MAX_10_EXP
141 /* but in any case prefer a value the compiler says */
142 long_double_digits
= LDBL_MAX_10_EXP
;
147 fmt
= strchr (fmt
, '%');
164 /* char, already accounted for by strlen(fmt) */
173 /* at most 3 digits per byte in hex, dec or octal, plus a sign */
174 total_width
+= 3 * integer_sizeof
+ 1;
178 /* Let's assume uintmax_t is the same size as intmax_t. */
180 (void) va_arg (ap
, intmax_t);
182 ASSERT_FAIL (intmax_t not available
);
186 (void) va_arg (ap
, long);
190 (void) va_arg (ap
, long long);
192 ASSERT_FAIL (long long not available
);
196 /* quad_t is probably the same as long long, but let's treat
197 it separately just to be sure. Also let's assume u_quad_t
198 will be the same size as quad_t. */
200 (void) va_arg (ap
, quad_t
);
202 ASSERT_FAIL (quad_t
not available
);
207 (void) va_arg (ap
, ptrdiff_t);
209 ASSERT_FAIL (ptrdiff_t not available
);
213 (void) va_arg (ap
, size_t);
216 /* default is an "int", and this includes h=short and hh=char
217 since they're promoted to int in a function call */
218 (void) va_arg (ap
, int);
227 /* Requested decimals, sign, point and e, plus an overestimate
228 of exponent digits (the assumption is all the float is
230 total_width
+= prec
+ 3 + floating_sizeof
* 3;
234 (void) va_arg (ap
, long double);
236 ASSERT_FAIL (long double not available
);
240 (void) va_arg (ap
, double);
244 /* Requested decimals, sign and point, and a margin for error,
245 then add the maximum digits that can be in the integer part,
246 based on the maximum exponent value. */
247 total_width
+= prec
+ 2 + 10;
251 (void) va_arg (ap
, long double);
252 total_width
+= long_double_digits
;
254 ASSERT_FAIL (long double not available
);
259 (void) va_arg (ap
, double);
260 total_width
+= double_digits
;
264 case 'h': /* short or char */
265 case 'j': /* intmax_t */
266 case 'L': /* long long or long double */
267 case 'q': /* quad_t */
268 case 't': /* ptrdiff_t */
274 /* long or long long */
277 type
= 'L'; /* "ll" means "L" */
281 /* bytes written, no output as such */
282 (void) va_arg (ap
, void *);
286 /* If no precision was given, then determine the string length
287 and put it there, to be added to the total under "next". If
288 a precision was given then that's already the maximum from
289 this field, but see whether the string is shorter than that,
290 in case the limit was very big. */
292 const char *s
= va_arg (ap
, const char *);
293 prec
= (seen_prec
? strnlen (s
, prec
) : strlen (s
));
298 /* pointer, let's assume at worst it's octal with some padding */
299 (void) va_arg (ap
, const void *);
300 total_width
+= 3 * sizeof (void *) + 16;
304 /* literal %, already accounted for by strlen(fmt) */
308 /* showbase, at most 2 for "0x" */
314 /* sign, already accounted for under numerics */
318 /* left justify, no effect on total width */
328 /* negative width means left justify which can be ignored,
329 negative prec would be invalid, just use absolute value */
330 int n
= va_arg (ap
, int);
335 case '0': case '1': case '2': case '3': case '4':
336 case '5': case '6': case '7': case '8': case '9':
337 /* process all digits to form a value */
341 n
= n
* 10 + (fchar
-'0');
343 } while (isascii (fchar
) && isdigit (fchar
));
344 fmt
--; /* unget the non-digit */
350 /* incomplete or invalid % sequence */
357 total_width
+= width
;
361 if (total_width
<= buf_size
)
363 vsprintf (buf
, orig_fmt
, orig_ap
);
370 s
= __GMP_ALLOCATE_FUNC_TYPE (total_width
, char);
371 vsprintf (s
, orig_fmt
, orig_ap
);
375 size_t copylen
= MIN (len
, buf_size
-1);
376 memcpy (buf
, s
, copylen
);
379 (*__gmp_free_func
) (s
, total_width
);
382 /* If total_width was somehow wrong then chances are we've already
383 clobbered memory, but maybe this check will still work. */
384 ASSERT_ALWAYS (len
< total_width
);
389 #endif /* ! HAVE_VSNPRINTF */