Annotation of OpenXM_contrib/gmp/printf/repl-vsnprintf.c, Revision 1.1.1.1
1.1 ohara 1: /* __gmp_replacement_vsnprintf -- for systems which don't have vsnprintf, or
2: only have a broken one.
3:
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.
7:
8: Copyright 2001, 2002 Free Software Foundation, Inc.
9:
10: This file is part of the GNU MP Library.
11:
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 2.1 of the License, or (at your
15: option) any later version.
16:
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.
21:
22: You should have received a copy of the GNU Lesser General Public License
23: along with the GNU MP Library; see the file COPYING.LIB. If not, write to
24: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25: MA 02111-1307, USA. */
26:
27: #define _GNU_SOURCE /* for strnlen prototype */
28:
29: #include "config.h"
30:
31: #if HAVE_STDARG
32: #include <stdarg.h>
33: #else
34: #include <varargs.h>
35: #endif
36:
37: #include <ctype.h> /* for isdigit */
38: #include <float.h> /* for DBL_MAX_10_EXP etc */
39: #include <stddef.h> /* for ptrdiff_t */
40: #include <string.h>
41: #include <stdio.h> /* for NULL */
42: #include <stdlib.h>
43:
44: #if HAVE_INTTYPES_H
45: # include <inttypes.h> /* for intmax_t */
46: #else
47: # if HAVE_STDINT_H
48: # include <stdint.h>
49: # endif
50: #endif
51:
52: #if HAVE_SYS_TYPES_H
53: #include <sys/types.h> /* for quad_t */
54: #endif
55:
56: #include "gmp.h"
57: #include "gmp-impl.h"
58:
59:
60: /* Autoconf notes that AIX 4.3 has a broken strnlen, but fortunately it
61: doesn't affect us since __gmp_replacement_vsnprintf is not required on
62: that system. */
63: #if ! HAVE_STRNLEN
64: static size_t
65: strnlen (const char *s, size_t n)
66: {
67: size_t i;
68: for (i = 0; i < n; i++)
69: if (s[i] == '\0')
70: break;
71: return i;
72: }
73: #endif
74:
75:
76: /* The approach here is to parse the fmt string, and decide how much space
77: it requires, then use vsprintf into a big enough buffer. The space
78: calculated isn't an exact amount, but it's certainly no less than
79: required.
80:
81: This code was inspired by GNU libiberty/vasprintf.c but we support more
82: datatypes, when available.
83:
84: mingw32 - doesn't have vsnprintf, it seems. Because gcc is used a full
85: set of types are available, but "long double" is just a plain IEEE
86: 64-bit "double", so we avoid the big 15-bit exponent estimate
87: (LDBL_MAX_EXP_10 is defined). */
88:
89: int
90: __gmp_replacement_vsnprintf (char *buf, size_t buf_size,
91: const char *orig_fmt, va_list orig_ap)
92: {
93: va_list ap;
94: const char *fmt;
95: size_t total_width, integer_sizeof, floating_sizeof, len;
96: char fchar, type;
97: int width, prec, seen_prec, double_digits, long_double_digits;
98: int *value;
99:
100: /* preserve orig_ap for use after size estimation */
101: va_copy (ap, orig_ap);
102:
103: fmt = orig_fmt;
104: total_width = strlen (fmt) + 1; /* 1 extra for the '\0' */
105:
106: integer_sizeof = sizeof (long);
107: #if HAVE_LONG_LONG
108: integer_sizeof = MAX (integer_sizeof, sizeof (long long));
109: #endif
110: #if HAVE_QUAD_T
111: integer_sizeof = MAX (integer_sizeof, sizeof (quad_t));
112: #endif
113:
114: floating_sizeof = sizeof (double);
115: #if HAVE_LONG_DOUBLE
116: floating_sizeof = MAX (floating_sizeof, sizeof (long double));
117: #endif
118:
119: /* IEEE double or VAX G floats have an 11 bit exponent, so the default is
120: a maximum 308 decimal digits. VAX D floats have only an 8 bit
121: exponent, but we don't bother trying to detect that directly. */
122: double_digits = 308;
123: #ifdef DBL_MAX_10_EXP
124: /* but case prefer a value the compiler says */
125: double_digits = DBL_MAX_10_EXP;
126: #endif
127:
128: /* IEEE 128-bit quad, Intel 80-bit temporary, or VAX H floats all have 15
129: bit exponents, so the default is a maximum 4932 decimal digits. */
130: long_double_digits = 4932;
131: /* but if double == long double, then go with that size */
132: #if HAVE_LONG_DOUBLE
133: if (sizeof (double) == sizeof (long double))
134: long_double_digits = double_digits;
135: #endif
136: #ifdef LDBL_MAX_10_EXP
137: /* but in any case prefer a value the compiler says */
138: long_double_digits = LDBL_MAX_10_EXP;
139: #endif
140:
141: for (;;)
142: {
143: fmt = strchr (fmt, '%');
144: if (fmt == NULL)
145: break;
146: fmt++;
147:
148: type = '\0';
149: width = 0;
150: prec = 6;
151: seen_prec = 0;
152: value = &width;
153:
154: for (;;)
155: {
156: fchar = *fmt++;
157: switch (fchar) {
158:
159: case 'c':
160: /* char, already accounted for by strlen(fmt) */
161: goto next;
162:
163: case 'd':
164: case 'i':
165: case 'o':
166: case 'x':
167: case 'X':
168: case 'u':
169: /* at most 3 digits per byte in hex, dec or octal, plus a sign */
170: total_width += 3 * integer_sizeof + 1;
171:
172: switch (type) {
173: case 'j':
174: /* Let's assume uintmax_t is the same size as intmax_t. */
175: #if HAVE_INTMAX_T
176: (void) va_arg (ap, intmax_t);
177: #else
178: ASSERT_FAIL (intmax_t not available);
179: #endif
180: break;
181: case 'l':
182: (void) va_arg (ap, long);
183: break;
184: case 'L':
185: #if HAVE_LONG_LONG
186: (void) va_arg (ap, long long);
187: #else
188: ASSERT_FAIL (long long not available);
189: #endif
190: break;
191: case 'q':
192: /* quad_t is probably the same as long long, but let's treat
193: it separately just to be sure. Also let's assume u_quad_t
194: will be the same size as quad_t. */
195: #if HAVE_QUAD_T
196: (void) va_arg (ap, quad_t);
197: #else
198: ASSERT_FAIL (quad_t not available);
199: #endif
200: break;
201: case 't':
202: #if HAVE_PTRDIFF_T
203: (void) va_arg (ap, ptrdiff_t);
204: #else
205: ASSERT_FAIL (ptrdiff_t not available);
206: #endif
207: break;
208: case 'z':
209: (void) va_arg (ap, size_t);
210: break;
211: default:
212: /* default is an "int", and this includes h=short and hh=char
213: since they're promoted to int in a function call */
214: (void) va_arg (ap, int);
215: break;
216: }
217: goto next;
218:
219: case 'E':
220: case 'e':
221: case 'G':
222: case 'g':
223: /* Requested decimals, sign, point and e, plus an overestimate
224: of exponent digits (the assumption is all the float is
225: exponent!). */
226: total_width += prec + 3 + floating_sizeof * 3;
227: if (type == 'L')
228: {
229: #if HAVE_LONG_DOUBLE
230: (void) va_arg (ap, long double);
231: #else
232: ASSERT_FAIL (long double not available);
233: #endif
234: }
235: else
236: (void) va_arg (ap, double);
237: break;
238:
239: case 'f':
240: /* Requested decimals, sign and point, and a margin for error,
241: then add the maximum digits that can be in the integer part,
242: based on the maximum exponent value. */
243: total_width += prec + 2 + 10;
244: if (type == 'L')
245: {
246: #if HAVE_LONG_DOUBLE
247: (void) va_arg (ap, long double);
248: total_width += long_double_digits;
249: #else
250: ASSERT_FAIL (long double not available);
251: #endif
252: }
253: else
254: {
255: (void) va_arg (ap, double);
256: total_width += double_digits;
257: }
258: break;
259:
260: case 'h': /* short or char */
261: case 'j': /* intmax_t */
262: case 'L': /* long long or long double */
263: case 'q': /* quad_t */
264: case 't': /* ptrdiff_t */
265: set_type:
266: type = fchar;
267: break;
268:
269: case 'l':
270: /* long or long long */
271: if (type != 'l')
272: goto set_type;
273: type = 'L'; /* "ll" means "L" */
274: break;
275:
276: case 'n':
277: /* bytes written, no output as such */
278: (void) va_arg (ap, void *);
279: goto next;
280:
281: case 's':
282: /* If no precision was given, then determine the string length
283: and put it there, to be added to the total under "next". If
284: a precision was given then that's already the maximum from
285: this field, but see whether the string is shorter than that,
286: in case the limit was very big. */
287: {
288: const char *s = va_arg (ap, const char *);
289: prec = (seen_prec ? strnlen (s, prec) : strlen (s));
290: }
291: goto next;
292:
293: case 'p':
294: /* pointer, let's assume at worst it's octal with some padding */
295: (void) va_arg (ap, const void *);
296: total_width += 3 * sizeof (void *) + 16;
297: goto next;
298:
299: case '%':
300: /* literal %, already accounted for by strlen(fmt) */
301: goto next;
302:
303: case '#':
304: /* showbase, at most 2 for "0x" */
305: total_width += 2;
306: break;
307:
308: case '+':
309: case ' ':
310: /* sign, already accounted for under numerics */
311: break;
312:
313: case '-':
314: /* left justify, no effect on total width */
315: break;
316:
317: case '.':
318: seen_prec = 1;
319: value = ≺
320: break;
321:
322: case '*':
323: {
324: /* negative width means left justify which can be ignored,
325: negative prec would be invalid, just use absolute value */
326: int n = va_arg (ap, int);
327: *value = ABS (n);
328: }
329: break;
330:
331: case '0': case '1': case '2': case '3': case '4':
332: case '5': case '6': case '7': case '8': case '9':
333: /* process all digits to form a value */
334: {
335: int n = 0;
336: do {
337: n = n * 10 + (fchar-'0');
338: fchar = *fmt++;
339: } while (isascii (fchar) && isdigit (fchar));
340: fmt--; /* unget the non-digit */
341: *value = n;
342: }
343: break;
344:
345: default:
346: /* incomplete or invalid % sequence */
347: ASSERT (0);
348: goto next;
349: }
350: }
351:
352: next:
353: total_width += width;
354: total_width += prec;
355: }
356:
357: if (total_width <= buf_size)
358: {
359: vsprintf (buf, orig_fmt, orig_ap);
360: len = strlen (buf);
361: }
362: else
363: {
364: char *s;
365:
366: s = __GMP_ALLOCATE_FUNC_TYPE (total_width, char);
367: vsprintf (s, orig_fmt, orig_ap);
368: len = strlen (s);
369: if (buf_size != 0)
370: {
371: size_t copylen = MIN (len, buf_size-1);
372: memcpy (buf, s, copylen);
373: buf[copylen] = '\0';
374: }
375: (*__gmp_free_func) (s, total_width);
376: }
377:
378: /* If total_width was somehow wrong then chances are we've already
379: clobbered memory, but maybe this check will still work. */
380: ASSERT_ALWAYS (len < total_width);
381:
382: return len;
383: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>