beta-0.89.2
[luatex.git] / source / libs / gmp / gmp-src / printf / repl-vsnprintf.c
bloba95003baa62e0d2b65d3e1d9dc9e4f15a2d74433
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
23 later version.
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
30 for more details.
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/. */
36 #include "config.h"
38 #if ! HAVE_VSNPRINTF /* only need this file if we don't have vsnprintf */
41 #define _GNU_SOURCE /* for strnlen prototype */
43 #include <stdarg.h>
44 #include <ctype.h> /* for isdigit */
45 #include <stddef.h> /* for ptrdiff_t */
46 #include <string.h>
47 #include <stdio.h> /* for NULL */
48 #include <stdlib.h>
50 #if HAVE_FLOAT_H
51 #include <float.h> /* for DBL_MAX_10_EXP etc */
52 #endif
54 #if HAVE_INTTYPES_H
55 # include <inttypes.h> /* for intmax_t */
56 #else
57 # if HAVE_STDINT_H
58 # include <stdint.h>
59 # endif
60 #endif
62 #if HAVE_SYS_TYPES_H
63 #include <sys/types.h> /* for quad_t */
64 #endif
66 #include "gmp.h"
67 #include "gmp-impl.h"
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
72 that system. */
73 #if ! HAVE_STRNLEN
74 static size_t
75 strnlen (const char *s, size_t n)
77 size_t i;
78 for (i = 0; i < n; i++)
79 if (s[i] == '\0')
80 break;
81 return i;
83 #endif
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
89 required.
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. */
99 int
100 __gmp_replacement_vsnprintf (char *buf, size_t buf_size,
101 const char *orig_fmt, va_list orig_ap)
103 va_list ap;
104 const char *fmt;
105 size_t total_width, integer_sizeof, floating_sizeof, len;
106 char fchar, type;
107 int width, prec, seen_prec, double_digits, long_double_digits;
108 int *value;
110 /* preserve orig_ap for use after size estimation */
111 va_copy (ap, orig_ap);
113 fmt = orig_fmt;
114 total_width = strlen (fmt) + 1; /* 1 extra for the '\0' */
116 integer_sizeof = sizeof (long);
117 #if HAVE_LONG_LONG
118 integer_sizeof = MAX (integer_sizeof, sizeof (long long));
119 #endif
120 #if HAVE_QUAD_T
121 integer_sizeof = MAX (integer_sizeof, sizeof (quad_t));
122 #endif
124 floating_sizeof = sizeof (double);
125 #if HAVE_LONG_DOUBLE
126 floating_sizeof = MAX (floating_sizeof, sizeof (long double));
127 #endif
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. */
132 double_digits = 308;
133 #ifdef DBL_MAX_10_EXP
134 /* but in any case prefer a value the compiler says */
135 double_digits = DBL_MAX_10_EXP;
136 #endif
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 */
142 #if HAVE_LONG_DOUBLE
143 if (sizeof (double) == sizeof (long double))
144 long_double_digits = double_digits;
145 #endif
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;
149 #endif
151 for (;;)
153 fmt = strchr (fmt, '%');
154 if (fmt == NULL)
155 break;
156 fmt++;
158 type = '\0';
159 width = 0;
160 prec = 6;
161 seen_prec = 0;
162 value = &width;
164 for (;;)
166 fchar = *fmt++;
167 switch (fchar) {
169 case 'c':
170 /* char, already accounted for by strlen(fmt) */
171 goto next;
173 case 'd':
174 case 'i':
175 case 'o':
176 case 'x':
177 case 'X':
178 case 'u':
179 /* at most 3 digits per byte in hex, dec or octal, plus a sign */
180 total_width += 3 * integer_sizeof + 1;
182 switch (type) {
183 case 'j':
184 /* Let's assume uintmax_t is the same size as intmax_t. */
185 #if HAVE_INTMAX_T
186 (void) va_arg (ap, intmax_t);
187 #else
188 ASSERT_FAIL (intmax_t not available);
189 #endif
190 break;
191 case 'l':
192 (void) va_arg (ap, long);
193 break;
194 case 'L':
195 #if HAVE_LONG_LONG
196 (void) va_arg (ap, long long);
197 #else
198 ASSERT_FAIL (long long not available);
199 #endif
200 break;
201 case 'q':
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. */
205 #if HAVE_QUAD_T
206 (void) va_arg (ap, quad_t);
207 #else
208 ASSERT_FAIL (quad_t not available);
209 #endif
210 break;
211 case 't':
212 #if HAVE_PTRDIFF_T
213 (void) va_arg (ap, ptrdiff_t);
214 #else
215 ASSERT_FAIL (ptrdiff_t not available);
216 #endif
217 break;
218 case 'z':
219 (void) va_arg (ap, size_t);
220 break;
221 default:
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);
225 break;
227 goto next;
229 case 'E':
230 case 'e':
231 case 'G':
232 case 'g':
233 /* Requested decimals, sign, point and e, plus an overestimate
234 of exponent digits (the assumption is all the float is
235 exponent!). */
236 total_width += prec + 3 + floating_sizeof * 3;
237 if (type == 'L')
239 #if HAVE_LONG_DOUBLE
240 (void) va_arg (ap, long double);
241 #else
242 ASSERT_FAIL (long double not available);
243 #endif
245 else
246 (void) va_arg (ap, double);
247 break;
249 case 'f':
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;
254 if (type == 'L')
256 #if HAVE_LONG_DOUBLE
257 (void) va_arg (ap, long double);
258 total_width += long_double_digits;
259 #else
260 ASSERT_FAIL (long double not available);
261 #endif
263 else
265 (void) va_arg (ap, double);
266 total_width += double_digits;
268 break;
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 */
276 set_type:
277 type = fchar;
278 break;
280 case 'l':
281 /* long or long long */
282 if (type != 'l')
283 goto set_type;
284 type = 'L'; /* "ll" means "L" */
285 break;
287 case 'n':
288 /* bytes written, no output as such */
289 (void) va_arg (ap, void *);
290 goto next;
292 case 's':
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));
302 goto next;
304 case 'p':
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;
308 goto next;
310 case '%':
311 /* literal %, already accounted for by strlen(fmt) */
312 goto next;
314 case '#':
315 /* showbase, at most 2 for "0x" */
316 total_width += 2;
317 break;
319 case '+':
320 case ' ':
321 /* sign, already accounted for under numerics */
322 break;
324 case '-':
325 /* left justify, no effect on total width */
326 break;
328 case '.':
329 seen_prec = 1;
330 value = &prec;
331 break;
333 case '*':
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);
338 *value = ABS (n);
340 break;
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 */
346 int n = 0;
347 do {
348 n = n * 10 + (fchar-'0');
349 fchar = *fmt++;
350 } while (isascii (fchar) && isdigit (fchar));
351 fmt--; /* unget the non-digit */
352 *value = n;
354 break;
356 default:
357 /* incomplete or invalid % sequence */
358 ASSERT (0);
359 goto next;
363 next:
364 total_width += width;
365 total_width += prec;
368 if (total_width <= buf_size)
370 vsprintf (buf, orig_fmt, orig_ap);
371 len = strlen (buf);
373 else
375 char *s;
377 s = __GMP_ALLOCATE_FUNC_TYPE (total_width, char);
378 vsprintf (s, orig_fmt, orig_ap);
379 len = strlen (s);
380 if (buf_size != 0)
382 size_t copylen = MIN (len, buf_size-1);
383 memcpy (buf, s, copylen);
384 buf[copylen] = '\0';
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);
393 return len;
396 #endif /* ! HAVE_VSNPRINTF */