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