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 */