Annotation of OpenXM_contrib/gmp/printf/repl-vsnprintf.c, Revision 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>