github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/printf/repl-vsnprintf.c (about) 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 either: 14 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. 18 19 or 20 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. 24 25 or both in parallel, as here. 26 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. 31 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/. */ 35 36 #include "config.h" 37 38 #if ! HAVE_VSNPRINTF /* only need this file if we don't have vsnprintf */ 39 40 41 #define _GNU_SOURCE /* for strnlen prototype */ 42 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> 49 50 #if HAVE_FLOAT_H 51 #include <float.h> /* for DBL_MAX_10_EXP etc */ 52 #endif 53 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 61 62 #if HAVE_SYS_TYPES_H 63 #include <sys/types.h> /* for quad_t */ 64 #endif 65 66 #include "gmp.h" 67 #include "gmp-impl.h" 68 69 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) 76 { 77 size_t i; 78 for (i = 0; i < n; i++) 79 if (s[i] == '\0') 80 break; 81 return i; 82 } 83 #endif 84 85 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. 90 91 This code was inspired by GNU libiberty/vasprintf.c but we support more 92 datatypes, when available. 93 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. */ 98 99 int 100 __gmp_replacement_vsnprintf (char *buf, size_t buf_size, 101 const char *orig_fmt, va_list orig_ap) 102 { 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; 109 110 /* preserve orig_ap for use after size estimation */ 111 va_copy (ap, orig_ap); 112 113 fmt = orig_fmt; 114 total_width = strlen (fmt) + 1; /* 1 extra for the '\0' */ 115 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 123 124 floating_sizeof = sizeof (double); 125 #if HAVE_LONG_DOUBLE 126 floating_sizeof = MAX (floating_sizeof, sizeof (long double)); 127 #endif 128 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 137 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 150 151 for (;;) 152 { 153 fmt = strchr (fmt, '%'); 154 if (fmt == NULL) 155 break; 156 fmt++; 157 158 type = '\0'; 159 width = 0; 160 prec = 6; 161 seen_prec = 0; 162 value = &width; 163 164 for (;;) 165 { 166 fchar = *fmt++; 167 switch (fchar) { 168 169 case 'c': 170 /* char, already accounted for by strlen(fmt) */ 171 goto next; 172 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; 181 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; 226 } 227 goto next; 228 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') 238 { 239 #if HAVE_LONG_DOUBLE 240 (void) va_arg (ap, long double); 241 #else 242 ASSERT_FAIL (long double not available); 243 #endif 244 } 245 else 246 (void) va_arg (ap, double); 247 break; 248 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') 255 { 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 262 } 263 else 264 { 265 (void) va_arg (ap, double); 266 total_width += double_digits; 267 } 268 break; 269 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; 279 280 case 'l': 281 /* long or long long */ 282 if (type != 'l') 283 goto set_type; 284 type = 'L'; /* "ll" means "L" */ 285 break; 286 287 case 'n': 288 /* bytes written, no output as such */ 289 (void) va_arg (ap, void *); 290 goto next; 291 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. */ 298 { 299 const char *s = va_arg (ap, const char *); 300 prec = (seen_prec ? strnlen (s, prec) : strlen (s)); 301 } 302 goto next; 303 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; 309 310 case '%': 311 /* literal %, already accounted for by strlen(fmt) */ 312 goto next; 313 314 case '#': 315 /* showbase, at most 2 for "0x" */ 316 total_width += 2; 317 break; 318 319 case '+': 320 case ' ': 321 /* sign, already accounted for under numerics */ 322 break; 323 324 case '-': 325 /* left justify, no effect on total width */ 326 break; 327 328 case '.': 329 seen_prec = 1; 330 value = ≺ 331 break; 332 333 case '*': 334 { 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); 339 } 340 break; 341 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 */ 345 { 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; 353 } 354 break; 355 356 default: 357 /* incomplete or invalid % sequence */ 358 ASSERT (0); 359 goto next; 360 } 361 } 362 363 next: 364 total_width += width; 365 total_width += prec; 366 } 367 368 if (total_width <= buf_size) 369 { 370 vsprintf (buf, orig_fmt, orig_ap); 371 len = strlen (buf); 372 } 373 else 374 { 375 char *s; 376 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) 381 { 382 size_t copylen = MIN (len, buf_size-1); 383 memcpy (buf, s, copylen); 384 buf[copylen] = '\0'; 385 } 386 (*__gmp_free_func) (s, total_width); 387 } 388 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); 392 393 return len; 394 } 395 396 #endif /* ! HAVE_VSNPRINTF */