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 3 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. If not, see http://www.gnu.org/licenses/. */ 24 25 #include "config.h" 26 27 #if ! HAVE_VSNPRINTF /* only need this file if we don't have vsnprintf */ 28 29 30 #define _GNU_SOURCE /* for strnlen prototype */ 31 32 #if HAVE_STDARG 33 #include <stdarg.h> 34 #else 35 #include <varargs.h> 36 #endif 37 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> 43 44 #if HAVE_FLOAT_H 45 #include <float.h> /* for DBL_MAX_10_EXP etc */ 46 #endif 47 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 55 56 #if HAVE_SYS_TYPES_H 57 #include <sys/types.h> /* for quad_t */ 58 #endif 59 60 #include "gmp.h" 61 #include "gmp-impl.h" 62 63 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) 70 { 71 size_t i; 72 for (i = 0; i < n; i++) 73 if (s[i] == '\0') 74 break; 75 return i; 76 } 77 #endif 78 79 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. 84 85 This code was inspired by GNU libiberty/vasprintf.c but we support more 86 datatypes, when available. 87 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. */ 92 93 int 94 __gmp_replacement_vsnprintf (char *buf, size_t buf_size, 95 const char *orig_fmt, va_list orig_ap) 96 { 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; 103 104 /* preserve orig_ap for use after size estimation */ 105 va_copy (ap, orig_ap); 106 107 fmt = orig_fmt; 108 total_width = strlen (fmt) + 1; /* 1 extra for the '\0' */ 109 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 117 118 floating_sizeof = sizeof (double); 119 #if HAVE_LONG_DOUBLE 120 floating_sizeof = MAX (floating_sizeof, sizeof (long double)); 121 #endif 122 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 131 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 144 145 for (;;) 146 { 147 fmt = strchr (fmt, '%'); 148 if (fmt == NULL) 149 break; 150 fmt++; 151 152 type = '\0'; 153 width = 0; 154 prec = 6; 155 seen_prec = 0; 156 value = &width; 157 158 for (;;) 159 { 160 fchar = *fmt++; 161 switch (fchar) { 162 163 case 'c': 164 /* char, already accounted for by strlen(fmt) */ 165 goto next; 166 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; 175 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; 220 } 221 goto next; 222 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') 232 { 233 #if HAVE_LONG_DOUBLE 234 (void) va_arg (ap, long double); 235 #else 236 ASSERT_FAIL (long double not available); 237 #endif 238 } 239 else 240 (void) va_arg (ap, double); 241 break; 242 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') 249 { 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 256 } 257 else 258 { 259 (void) va_arg (ap, double); 260 total_width += double_digits; 261 } 262 break; 263 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; 272 273 case 'l': 274 /* long or long long */ 275 if (type != 'l') 276 goto set_type; 277 type = 'L'; /* "ll" means "L" */ 278 break; 279 280 case 'n': 281 /* bytes written, no output as such */ 282 (void) va_arg (ap, void *); 283 goto next; 284 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. */ 291 { 292 const char *s = va_arg (ap, const char *); 293 prec = (seen_prec ? strnlen (s, prec) : strlen (s)); 294 } 295 goto next; 296 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; 302 303 case '%': 304 /* literal %, already accounted for by strlen(fmt) */ 305 goto next; 306 307 case '#': 308 /* showbase, at most 2 for "0x" */ 309 total_width += 2; 310 break; 311 312 case '+': 313 case ' ': 314 /* sign, already accounted for under numerics */ 315 break; 316 317 case '-': 318 /* left justify, no effect on total width */ 319 break; 320 321 case '.': 322 seen_prec = 1; 323 value = ≺ 324 break; 325 326 case '*': 327 { 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); 332 } 333 break; 334 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 */ 338 { 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; 346 } 347 break; 348 349 default: 350 /* incomplete or invalid % sequence */ 351 ASSERT (0); 352 goto next; 353 } 354 } 355 356 next: 357 total_width += width; 358 total_width += prec; 359 } 360 361 if (total_width <= buf_size) 362 { 363 vsprintf (buf, orig_fmt, orig_ap); 364 len = strlen (buf); 365 } 366 else 367 { 368 char *s; 369 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) 374 { 375 size_t copylen = MIN (len, buf_size-1); 376 memcpy (buf, s, copylen); 377 buf[copylen] = '\0'; 378 } 379 (*__gmp_free_func) (s, total_width); 380 } 381 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); 385 386 return len; 387 } 388 389 #endif /* ! HAVE_VSNPRINTF */ 390