dhcpcd: update README.DRAGONFLY
[dragonfly.git] / contrib / gmp / printf / repl-vsnprintf.c
blob06809dcb82d9aaf4b7901edaffca4bcb19d87f61
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/. */
25 #include "config.h"
27 #if ! HAVE_VSNPRINTF /* only need this file if we don't have vsnprintf */
30 #define _GNU_SOURCE /* for strnlen prototype */
32 #if HAVE_STDARG
33 #include <stdarg.h>
34 #else
35 #include <varargs.h>
36 #endif
38 #include <ctype.h> /* for isdigit */
39 #include <stddef.h> /* for ptrdiff_t */
40 #include <string.h>
41 #include <stdio.h> /* for NULL */
42 #include <stdlib.h>
44 #if HAVE_FLOAT_H
45 #include <float.h> /* for DBL_MAX_10_EXP etc */
46 #endif
48 #if HAVE_INTTYPES_H
49 # include <inttypes.h> /* for intmax_t */
50 #else
51 # if HAVE_STDINT_H
52 # include <stdint.h>
53 # endif
54 #endif
56 #if HAVE_SYS_TYPES_H
57 #include <sys/types.h> /* for quad_t */
58 #endif
60 #include "gmp.h"
61 #include "gmp-impl.h"
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
66 that system. */
67 #if ! HAVE_STRNLEN
68 static size_t
69 strnlen (const char *s, size_t n)
71 size_t i;
72 for (i = 0; i < n; i++)
73 if (s[i] == '\0')
74 break;
75 return i;
77 #endif
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
83 required.
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. */
93 int
94 __gmp_replacement_vsnprintf (char *buf, size_t buf_size,
95 const char *orig_fmt, va_list orig_ap)
97 va_list ap;
98 const char *fmt;
99 size_t total_width, integer_sizeof, floating_sizeof, len;
100 char fchar, type;
101 int width, prec, seen_prec, double_digits, long_double_digits;
102 int *value;
104 /* preserve orig_ap for use after size estimation */
105 va_copy (ap, orig_ap);
107 fmt = orig_fmt;
108 total_width = strlen (fmt) + 1; /* 1 extra for the '\0' */
110 integer_sizeof = sizeof (long);
111 #if HAVE_LONG_LONG
112 integer_sizeof = MAX (integer_sizeof, sizeof (long long));
113 #endif
114 #if HAVE_QUAD_T
115 integer_sizeof = MAX (integer_sizeof, sizeof (quad_t));
116 #endif
118 floating_sizeof = sizeof (double);
119 #if HAVE_LONG_DOUBLE
120 floating_sizeof = MAX (floating_sizeof, sizeof (long double));
121 #endif
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. */
126 double_digits = 308;
127 #ifdef DBL_MAX_10_EXP
128 /* but in any case prefer a value the compiler says */
129 double_digits = DBL_MAX_10_EXP;
130 #endif
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 */
136 #if HAVE_LONG_DOUBLE
137 if (sizeof (double) == sizeof (long double))
138 long_double_digits = double_digits;
139 #endif
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;
143 #endif
145 for (;;)
147 fmt = strchr (fmt, '%');
148 if (fmt == NULL)
149 break;
150 fmt++;
152 type = '\0';
153 width = 0;
154 prec = 6;
155 seen_prec = 0;
156 value = &width;
158 for (;;)
160 fchar = *fmt++;
161 switch (fchar) {
163 case 'c':
164 /* char, already accounted for by strlen(fmt) */
165 goto next;
167 case 'd':
168 case 'i':
169 case 'o':
170 case 'x':
171 case 'X':
172 case 'u':
173 /* at most 3 digits per byte in hex, dec or octal, plus a sign */
174 total_width += 3 * integer_sizeof + 1;
176 switch (type) {
177 case 'j':
178 /* Let's assume uintmax_t is the same size as intmax_t. */
179 #if HAVE_INTMAX_T
180 (void) va_arg (ap, intmax_t);
181 #else
182 ASSERT_FAIL (intmax_t not available);
183 #endif
184 break;
185 case 'l':
186 (void) va_arg (ap, long);
187 break;
188 case 'L':
189 #if HAVE_LONG_LONG
190 (void) va_arg (ap, long long);
191 #else
192 ASSERT_FAIL (long long not available);
193 #endif
194 break;
195 case 'q':
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. */
199 #if HAVE_QUAD_T
200 (void) va_arg (ap, quad_t);
201 #else
202 ASSERT_FAIL (quad_t not available);
203 #endif
204 break;
205 case 't':
206 #if HAVE_PTRDIFF_T
207 (void) va_arg (ap, ptrdiff_t);
208 #else
209 ASSERT_FAIL (ptrdiff_t not available);
210 #endif
211 break;
212 case 'z':
213 (void) va_arg (ap, size_t);
214 break;
215 default:
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);
219 break;
221 goto next;
223 case 'E':
224 case 'e':
225 case 'G':
226 case 'g':
227 /* Requested decimals, sign, point and e, plus an overestimate
228 of exponent digits (the assumption is all the float is
229 exponent!). */
230 total_width += prec + 3 + floating_sizeof * 3;
231 if (type == 'L')
233 #if HAVE_LONG_DOUBLE
234 (void) va_arg (ap, long double);
235 #else
236 ASSERT_FAIL (long double not available);
237 #endif
239 else
240 (void) va_arg (ap, double);
241 break;
243 case 'f':
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;
248 if (type == 'L')
250 #if HAVE_LONG_DOUBLE
251 (void) va_arg (ap, long double);
252 total_width += long_double_digits;
253 #else
254 ASSERT_FAIL (long double not available);
255 #endif
257 else
259 (void) va_arg (ap, double);
260 total_width += double_digits;
262 break;
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 */
269 set_type:
270 type = fchar;
271 break;
273 case 'l':
274 /* long or long long */
275 if (type != 'l')
276 goto set_type;
277 type = 'L'; /* "ll" means "L" */
278 break;
280 case 'n':
281 /* bytes written, no output as such */
282 (void) va_arg (ap, void *);
283 goto next;
285 case 's':
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));
295 goto next;
297 case 'p':
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;
301 goto next;
303 case '%':
304 /* literal %, already accounted for by strlen(fmt) */
305 goto next;
307 case '#':
308 /* showbase, at most 2 for "0x" */
309 total_width += 2;
310 break;
312 case '+':
313 case ' ':
314 /* sign, already accounted for under numerics */
315 break;
317 case '-':
318 /* left justify, no effect on total width */
319 break;
321 case '.':
322 seen_prec = 1;
323 value = &prec;
324 break;
326 case '*':
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);
331 *value = ABS (n);
333 break;
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 */
339 int n = 0;
340 do {
341 n = n * 10 + (fchar-'0');
342 fchar = *fmt++;
343 } while (isascii (fchar) && isdigit (fchar));
344 fmt--; /* unget the non-digit */
345 *value = n;
347 break;
349 default:
350 /* incomplete or invalid % sequence */
351 ASSERT (0);
352 goto next;
356 next:
357 total_width += width;
358 total_width += prec;
361 if (total_width <= buf_size)
363 vsprintf (buf, orig_fmt, orig_ap);
364 len = strlen (buf);
366 else
368 char *s;
370 s = __GMP_ALLOCATE_FUNC_TYPE (total_width, char);
371 vsprintf (s, orig_fmt, orig_ap);
372 len = strlen (s);
373 if (buf_size != 0)
375 size_t copylen = MIN (len, buf_size-1);
376 memcpy (buf, s, copylen);
377 buf[copylen] = '\0';
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);
386 return len;
389 #endif /* ! HAVE_VSNPRINTF */