1 /* $NetBSD: vasnprintf.c,v 1.1.1.1 2016/01/14 00:11:28 christos Exp $ */ 2 3 /* vsprintf with automatic memory allocation. 4 Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc. 5 6 This program is free software; you can redistribute it and/or modify it 7 under the terms of the GNU Library General Public License as published 8 by the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Library General Public License for more details. 15 16 You should have received a copy of the GNU Library General Public 17 License along with this program; if not, write to the Free Software 18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 19 USA. */ 20 21 /* Tell glibc's <stdio.h> to provide a prototype for snprintf(). 22 This must come before <config.h> because <config.h> may include 23 <features.h>, and once <features.h> has been included, it's too late. */ 24 #ifndef _GNU_SOURCE 25 # define _GNU_SOURCE 1 26 #endif 27 28 #ifdef HAVE_CONFIG_H 29 # include <config.h> 30 #endif 31 #ifndef IN_LIBINTL 32 # include <alloca.h> 33 #endif 34 35 /* Specification. */ 36 #if WIDE_CHAR_VERSION 37 # include "vasnwprintf.h" 38 #else 39 # include "vasnprintf.h" 40 #endif 41 42 #include <stdio.h> /* snprintf(), sprintf() */ 43 #include <stdlib.h> /* abort(), malloc(), realloc(), free() */ 44 #include <string.h> /* memcpy(), strlen() */ 45 #include <errno.h> /* errno */ 46 #include <limits.h> /* CHAR_BIT */ 47 #include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */ 48 #if WIDE_CHAR_VERSION 49 # include "wprintf-parse.h" 50 #else 51 # include "printf-parse.h" 52 #endif 53 54 /* Checked size_t computations. */ 55 #include "xsize.h" 56 57 #ifdef HAVE_WCHAR_T 58 # ifdef HAVE_WCSLEN 59 # define local_wcslen wcslen 60 # else 61 /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid 62 a dependency towards this library, here is a local substitute. 63 Define this substitute only once, even if this file is included 64 twice in the same compilation unit. */ 65 # ifndef local_wcslen_defined 66 # define local_wcslen_defined 1 67 static size_t 68 local_wcslen (const wchar_t *s) 69 { 70 const wchar_t *ptr; 71 72 for (ptr = s; *ptr != (wchar_t) 0; ptr++) 73 ; 74 return ptr - s; 75 } 76 # endif 77 # endif 78 #endif 79 80 #if WIDE_CHAR_VERSION 81 # define VASNPRINTF vasnwprintf 82 # define CHAR_T wchar_t 83 # define DIRECTIVE wchar_t_directive 84 # define DIRECTIVES wchar_t_directives 85 # define PRINTF_PARSE wprintf_parse 86 # define USE_SNPRINTF 1 87 # if HAVE_DECL__SNWPRINTF 88 /* On Windows, the function swprintf() has a different signature than 89 on Unix; we use the _snwprintf() function instead. */ 90 # define SNPRINTF _snwprintf 91 # else 92 /* Unix. */ 93 # define SNPRINTF swprintf 94 # endif 95 #else 96 # define VASNPRINTF vasnprintf 97 # define CHAR_T char 98 # define DIRECTIVE char_directive 99 # define DIRECTIVES char_directives 100 # define PRINTF_PARSE printf_parse 101 # define USE_SNPRINTF (HAVE_DECL__SNPRINTF || HAVE_SNPRINTF) 102 # if HAVE_DECL__SNPRINTF 103 /* Windows. */ 104 # define SNPRINTF _snprintf 105 # else 106 /* Unix. */ 107 # define SNPRINTF snprintf 108 # endif 109 #endif 110 111 CHAR_T * 112 VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args) 113 { 114 DIRECTIVES d; 115 arguments a; 116 117 if (PRINTF_PARSE (format, &d, &a) < 0) 118 { 119 errno = EINVAL; 120 return NULL; 121 } 122 123 #define CLEANUP() \ 124 free (d.dir); \ 125 if (a.arg) \ 126 free (a.arg); 127 128 if (printf_fetchargs (args, &a) < 0) 129 { 130 CLEANUP (); 131 errno = EINVAL; 132 return NULL; 133 } 134 135 { 136 size_t buf_neededlength; 137 CHAR_T *buf; 138 CHAR_T *buf_malloced; 139 const CHAR_T *cp; 140 size_t i; 141 DIRECTIVE *dp; 142 /* Output string accumulator. */ 143 CHAR_T *result; 144 size_t allocated; 145 size_t length; 146 147 /* Allocate a small buffer that will hold a directive passed to 148 sprintf or snprintf. */ 149 buf_neededlength = 150 xsum4 (7, d.max_width_length, d.max_precision_length, 6); 151 #if HAVE_ALLOCA 152 if (buf_neededlength < 4000 / sizeof (CHAR_T)) 153 { 154 buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T)); 155 buf_malloced = NULL; 156 } 157 else 158 #endif 159 { 160 size_t buf_memsize = xtimes (buf_neededlength, sizeof (CHAR_T)); 161 if (size_overflow_p (buf_memsize)) 162 goto out_of_memory_1; 163 buf = (CHAR_T *) malloc (buf_memsize); 164 if (buf == NULL) 165 goto out_of_memory_1; 166 buf_malloced = buf; 167 } 168 169 if (resultbuf != NULL) 170 { 171 result = resultbuf; 172 allocated = *lengthp; 173 } 174 else 175 { 176 result = NULL; 177 allocated = 0; 178 } 179 length = 0; 180 /* Invariants: 181 result is either == resultbuf or == NULL or malloc-allocated. 182 If length > 0, then result != NULL. */ 183 184 /* Ensures that allocated >= needed. Aborts through a jump to 185 out_of_memory if needed is SIZE_MAX or otherwise too big. */ 186 #define ENSURE_ALLOCATION(needed) \ 187 if ((needed) > allocated) \ 188 { \ 189 size_t memory_size; \ 190 CHAR_T *memory; \ 191 \ 192 allocated = (allocated > 0 ? xtimes (allocated, 2) : 12); \ 193 if ((needed) > allocated) \ 194 allocated = (needed); \ 195 memory_size = xtimes (allocated, sizeof (CHAR_T)); \ 196 if (size_overflow_p (memory_size)) \ 197 goto out_of_memory; \ 198 if (result == resultbuf || result == NULL) \ 199 memory = (CHAR_T *) malloc (memory_size); \ 200 else \ 201 memory = (CHAR_T *) realloc (result, memory_size); \ 202 if (memory == NULL) \ 203 goto out_of_memory; \ 204 if (result == resultbuf && length > 0) \ 205 memcpy (memory, result, length * sizeof (CHAR_T)); \ 206 result = memory; \ 207 } 208 209 for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++) 210 { 211 if (cp != dp->dir_start) 212 { 213 size_t n = dp->dir_start - cp; 214 size_t augmented_length = xsum (length, n); 215 216 ENSURE_ALLOCATION (augmented_length); 217 memcpy (result + length, cp, n * sizeof (CHAR_T)); 218 length = augmented_length; 219 } 220 if (i == d.count) 221 break; 222 223 /* Execute a single directive. */ 224 if (dp->conversion == '%') 225 { 226 size_t augmented_length; 227 228 if (!(dp->arg_index == ARG_NONE)) 229 abort (); 230 augmented_length = xsum (length, 1); 231 ENSURE_ALLOCATION (augmented_length); 232 result[length] = '%'; 233 length = augmented_length; 234 } 235 else 236 { 237 if (!(dp->arg_index != ARG_NONE)) 238 abort (); 239 240 if (dp->conversion == 'n') 241 { 242 switch (a.arg[dp->arg_index].type) 243 { 244 case TYPE_COUNT_SCHAR_POINTER: 245 *a.arg[dp->arg_index].a.a_count_schar_pointer = length; 246 break; 247 case TYPE_COUNT_SHORT_POINTER: 248 *a.arg[dp->arg_index].a.a_count_short_pointer = length; 249 break; 250 case TYPE_COUNT_INT_POINTER: 251 *a.arg[dp->arg_index].a.a_count_int_pointer = length; 252 break; 253 case TYPE_COUNT_LONGINT_POINTER: 254 *a.arg[dp->arg_index].a.a_count_longint_pointer = length; 255 break; 256 #ifdef HAVE_LONG_LONG 257 case TYPE_COUNT_LONGLONGINT_POINTER: 258 *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length; 259 break; 260 #endif 261 default: 262 abort (); 263 } 264 } 265 else 266 { 267 arg_type type = a.arg[dp->arg_index].type; 268 CHAR_T *p; 269 unsigned int prefix_count; 270 int prefixes[2]; 271 #if !USE_SNPRINTF 272 size_t tmp_length; 273 CHAR_T tmpbuf[700]; 274 CHAR_T *tmp; 275 276 /* Allocate a temporary buffer of sufficient size for calling 277 sprintf. */ 278 { 279 size_t width; 280 size_t precision; 281 282 width = 0; 283 if (dp->width_start != dp->width_end) 284 { 285 if (dp->width_arg_index != ARG_NONE) 286 { 287 int arg; 288 289 if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) 290 abort (); 291 arg = a.arg[dp->width_arg_index].a.a_int; 292 width = (arg < 0 ? (unsigned int) (-arg) : arg); 293 } 294 else 295 { 296 const CHAR_T *digitp = dp->width_start; 297 298 do 299 width = xsum (xtimes (width, 10), *digitp++ - '0'); 300 while (digitp != dp->width_end); 301 } 302 } 303 304 precision = 6; 305 if (dp->precision_start != dp->precision_end) 306 { 307 if (dp->precision_arg_index != ARG_NONE) 308 { 309 int arg; 310 311 if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) 312 abort (); 313 arg = a.arg[dp->precision_arg_index].a.a_int; 314 precision = (arg < 0 ? 0 : arg); 315 } 316 else 317 { 318 const CHAR_T *digitp = dp->precision_start + 1; 319 320 precision = 0; 321 do 322 precision = xsum (xtimes (precision, 10), *digitp++ - '0'); 323 while (digitp != dp->precision_end); 324 } 325 } 326 327 switch (dp->conversion) 328 { 329 330 case 'd': case 'i': case 'u': 331 # ifdef HAVE_LONG_LONG 332 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) 333 tmp_length = 334 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT 335 * 0.30103 /* binary -> decimal */ 336 * 2 /* estimate for FLAG_GROUP */ 337 ) 338 + 1 /* turn floor into ceil */ 339 + 1; /* account for leading sign */ 340 else 341 # endif 342 if (type == TYPE_LONGINT || type == TYPE_ULONGINT) 343 tmp_length = 344 (unsigned int) (sizeof (unsigned long) * CHAR_BIT 345 * 0.30103 /* binary -> decimal */ 346 * 2 /* estimate for FLAG_GROUP */ 347 ) 348 + 1 /* turn floor into ceil */ 349 + 1; /* account for leading sign */ 350 else 351 tmp_length = 352 (unsigned int) (sizeof (unsigned int) * CHAR_BIT 353 * 0.30103 /* binary -> decimal */ 354 * 2 /* estimate for FLAG_GROUP */ 355 ) 356 + 1 /* turn floor into ceil */ 357 + 1; /* account for leading sign */ 358 break; 359 360 case 'o': 361 # ifdef HAVE_LONG_LONG 362 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) 363 tmp_length = 364 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT 365 * 0.333334 /* binary -> octal */ 366 ) 367 + 1 /* turn floor into ceil */ 368 + 1; /* account for leading sign */ 369 else 370 # endif 371 if (type == TYPE_LONGINT || type == TYPE_ULONGINT) 372 tmp_length = 373 (unsigned int) (sizeof (unsigned long) * CHAR_BIT 374 * 0.333334 /* binary -> octal */ 375 ) 376 + 1 /* turn floor into ceil */ 377 + 1; /* account for leading sign */ 378 else 379 tmp_length = 380 (unsigned int) (sizeof (unsigned int) * CHAR_BIT 381 * 0.333334 /* binary -> octal */ 382 ) 383 + 1 /* turn floor into ceil */ 384 + 1; /* account for leading sign */ 385 break; 386 387 case 'x': case 'X': 388 # ifdef HAVE_LONG_LONG 389 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) 390 tmp_length = 391 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT 392 * 0.25 /* binary -> hexadecimal */ 393 ) 394 + 1 /* turn floor into ceil */ 395 + 2; /* account for leading sign or alternate form */ 396 else 397 # endif 398 if (type == TYPE_LONGINT || type == TYPE_ULONGINT) 399 tmp_length = 400 (unsigned int) (sizeof (unsigned long) * CHAR_BIT 401 * 0.25 /* binary -> hexadecimal */ 402 ) 403 + 1 /* turn floor into ceil */ 404 + 2; /* account for leading sign or alternate form */ 405 else 406 tmp_length = 407 (unsigned int) (sizeof (unsigned int) * CHAR_BIT 408 * 0.25 /* binary -> hexadecimal */ 409 ) 410 + 1 /* turn floor into ceil */ 411 + 2; /* account for leading sign or alternate form */ 412 break; 413 414 case 'f': case 'F': 415 # ifdef HAVE_LONG_DOUBLE 416 if (type == TYPE_LONGDOUBLE) 417 tmp_length = 418 (unsigned int) (LDBL_MAX_EXP 419 * 0.30103 /* binary -> decimal */ 420 * 2 /* estimate for FLAG_GROUP */ 421 ) 422 + 1 /* turn floor into ceil */ 423 + 10; /* sign, decimal point etc. */ 424 else 425 # endif 426 tmp_length = 427 (unsigned int) (DBL_MAX_EXP 428 * 0.30103 /* binary -> decimal */ 429 * 2 /* estimate for FLAG_GROUP */ 430 ) 431 + 1 /* turn floor into ceil */ 432 + 10; /* sign, decimal point etc. */ 433 tmp_length = xsum (tmp_length, precision); 434 break; 435 436 case 'e': case 'E': case 'g': case 'G': 437 case 'a': case 'A': 438 tmp_length = 439 12; /* sign, decimal point, exponent etc. */ 440 tmp_length = xsum (tmp_length, precision); 441 break; 442 443 case 'c': 444 # if defined HAVE_WINT_T && !WIDE_CHAR_VERSION 445 if (type == TYPE_WIDE_CHAR) 446 tmp_length = MB_CUR_MAX; 447 else 448 # endif 449 tmp_length = 1; 450 break; 451 452 case 's': 453 # ifdef HAVE_WCHAR_T 454 if (type == TYPE_WIDE_STRING) 455 { 456 tmp_length = 457 local_wcslen (a.arg[dp->arg_index].a.a_wide_string); 458 459 # if !WIDE_CHAR_VERSION 460 tmp_length = xtimes (tmp_length, MB_CUR_MAX); 461 # endif 462 } 463 else 464 # endif 465 tmp_length = strlen (a.arg[dp->arg_index].a.a_string); 466 break; 467 468 case 'p': 469 tmp_length = 470 (unsigned int) (sizeof (void *) * CHAR_BIT 471 * 0.25 /* binary -> hexadecimal */ 472 ) 473 + 1 /* turn floor into ceil */ 474 + 2; /* account for leading 0x */ 475 break; 476 477 default: 478 abort (); 479 } 480 481 if (tmp_length < width) 482 tmp_length = width; 483 484 tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */ 485 } 486 487 if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T)) 488 tmp = tmpbuf; 489 else 490 { 491 size_t tmp_memsize = xtimes (tmp_length, sizeof (CHAR_T)); 492 493 if (size_overflow_p (tmp_memsize)) 494 /* Overflow, would lead to out of memory. */ 495 goto out_of_memory; 496 tmp = (CHAR_T *) malloc (tmp_memsize); 497 if (tmp == NULL) 498 /* Out of memory. */ 499 goto out_of_memory; 500 } 501 #endif 502 503 /* Construct the format string for calling snprintf or 504 sprintf. */ 505 p = buf; 506 *p++ = '%'; 507 if (dp->flags & FLAG_GROUP) 508 *p++ = '\''; 509 if (dp->flags & FLAG_LEFT) 510 *p++ = '-'; 511 if (dp->flags & FLAG_SHOWSIGN) 512 *p++ = '+'; 513 if (dp->flags & FLAG_SPACE) 514 *p++ = ' '; 515 if (dp->flags & FLAG_ALT) 516 *p++ = '#'; 517 if (dp->flags & FLAG_ZERO) 518 *p++ = '0'; 519 if (dp->width_start != dp->width_end) 520 { 521 size_t n = dp->width_end - dp->width_start; 522 memcpy (p, dp->width_start, n * sizeof (CHAR_T)); 523 p += n; 524 } 525 if (dp->precision_start != dp->precision_end) 526 { 527 size_t n = dp->precision_end - dp->precision_start; 528 memcpy (p, dp->precision_start, n * sizeof (CHAR_T)); 529 p += n; 530 } 531 532 switch (type) 533 { 534 #ifdef HAVE_LONG_LONG 535 case TYPE_LONGLONGINT: 536 case TYPE_ULONGLONGINT: 537 *p++ = 'l'; 538 /*FALLTHROUGH*/ 539 #endif 540 case TYPE_LONGINT: 541 case TYPE_ULONGINT: 542 #ifdef HAVE_WINT_T 543 case TYPE_WIDE_CHAR: 544 #endif 545 #ifdef HAVE_WCHAR_T 546 case TYPE_WIDE_STRING: 547 #endif 548 *p++ = 'l'; 549 break; 550 #ifdef HAVE_LONG_DOUBLE 551 case TYPE_LONGDOUBLE: 552 *p++ = 'L'; 553 break; 554 #endif 555 default: 556 break; 557 } 558 *p = dp->conversion; 559 #if USE_SNPRINTF 560 p[1] = '%'; 561 p[2] = 'n'; 562 p[3] = '\0'; 563 #else 564 p[1] = '\0'; 565 #endif 566 567 /* Construct the arguments for calling snprintf or sprintf. */ 568 prefix_count = 0; 569 if (dp->width_arg_index != ARG_NONE) 570 { 571 if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) 572 abort (); 573 prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int; 574 } 575 if (dp->precision_arg_index != ARG_NONE) 576 { 577 if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) 578 abort (); 579 prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int; 580 } 581 582 #if USE_SNPRINTF 583 /* Prepare checking whether snprintf returns the count 584 via %n. */ 585 ENSURE_ALLOCATION (xsum (length, 1)); 586 result[length] = '\0'; 587 #endif 588 589 for (;;) 590 { 591 size_t maxlen; 592 int count; 593 int retcount; 594 595 maxlen = allocated - length; 596 count = -1; 597 retcount = 0; 598 599 #if USE_SNPRINTF 600 # define SNPRINTF_BUF(arg) \ 601 switch (prefix_count) \ 602 { \ 603 case 0: \ 604 retcount = SNPRINTF (result + length, maxlen, buf, \ 605 arg, &count); \ 606 break; \ 607 case 1: \ 608 retcount = SNPRINTF (result + length, maxlen, buf, \ 609 prefixes[0], arg, &count); \ 610 break; \ 611 case 2: \ 612 retcount = SNPRINTF (result + length, maxlen, buf, \ 613 prefixes[0], prefixes[1], arg, \ 614 &count); \ 615 break; \ 616 default: \ 617 abort (); \ 618 } 619 #else 620 # define SNPRINTF_BUF(arg) \ 621 switch (prefix_count) \ 622 { \ 623 case 0: \ 624 count = sprintf (tmp, buf, arg); \ 625 break; \ 626 case 1: \ 627 count = sprintf (tmp, buf, prefixes[0], arg); \ 628 break; \ 629 case 2: \ 630 count = sprintf (tmp, buf, prefixes[0], prefixes[1],\ 631 arg); \ 632 break; \ 633 default: \ 634 abort (); \ 635 } 636 #endif 637 638 switch (type) 639 { 640 case TYPE_SCHAR: 641 { 642 int arg = a.arg[dp->arg_index].a.a_schar; 643 SNPRINTF_BUF (arg); 644 } 645 break; 646 case TYPE_UCHAR: 647 { 648 unsigned int arg = a.arg[dp->arg_index].a.a_uchar; 649 SNPRINTF_BUF (arg); 650 } 651 break; 652 case TYPE_SHORT: 653 { 654 int arg = a.arg[dp->arg_index].a.a_short; 655 SNPRINTF_BUF (arg); 656 } 657 break; 658 case TYPE_USHORT: 659 { 660 unsigned int arg = a.arg[dp->arg_index].a.a_ushort; 661 SNPRINTF_BUF (arg); 662 } 663 break; 664 case TYPE_INT: 665 { 666 int arg = a.arg[dp->arg_index].a.a_int; 667 SNPRINTF_BUF (arg); 668 } 669 break; 670 case TYPE_UINT: 671 { 672 unsigned int arg = a.arg[dp->arg_index].a.a_uint; 673 SNPRINTF_BUF (arg); 674 } 675 break; 676 case TYPE_LONGINT: 677 { 678 long int arg = a.arg[dp->arg_index].a.a_longint; 679 SNPRINTF_BUF (arg); 680 } 681 break; 682 case TYPE_ULONGINT: 683 { 684 unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint; 685 SNPRINTF_BUF (arg); 686 } 687 break; 688 #ifdef HAVE_LONG_LONG 689 case TYPE_LONGLONGINT: 690 { 691 long long int arg = a.arg[dp->arg_index].a.a_longlongint; 692 SNPRINTF_BUF (arg); 693 } 694 break; 695 case TYPE_ULONGLONGINT: 696 { 697 unsigned long long int arg = a.arg[dp->arg_index].a.a_ulonglongint; 698 SNPRINTF_BUF (arg); 699 } 700 break; 701 #endif 702 case TYPE_DOUBLE: 703 { 704 double arg = a.arg[dp->arg_index].a.a_double; 705 SNPRINTF_BUF (arg); 706 } 707 break; 708 #ifdef HAVE_LONG_DOUBLE 709 case TYPE_LONGDOUBLE: 710 { 711 long double arg = a.arg[dp->arg_index].a.a_longdouble; 712 SNPRINTF_BUF (arg); 713 } 714 break; 715 #endif 716 case TYPE_CHAR: 717 { 718 int arg = a.arg[dp->arg_index].a.a_char; 719 SNPRINTF_BUF (arg); 720 } 721 break; 722 #ifdef HAVE_WINT_T 723 case TYPE_WIDE_CHAR: 724 { 725 wint_t arg = a.arg[dp->arg_index].a.a_wide_char; 726 SNPRINTF_BUF (arg); 727 } 728 break; 729 #endif 730 case TYPE_STRING: 731 { 732 const char *arg = a.arg[dp->arg_index].a.a_string; 733 SNPRINTF_BUF (arg); 734 } 735 break; 736 #ifdef HAVE_WCHAR_T 737 case TYPE_WIDE_STRING: 738 { 739 const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string; 740 SNPRINTF_BUF (arg); 741 } 742 break; 743 #endif 744 case TYPE_POINTER: 745 { 746 void *arg = a.arg[dp->arg_index].a.a_pointer; 747 SNPRINTF_BUF (arg); 748 } 749 break; 750 default: 751 abort (); 752 } 753 754 #if USE_SNPRINTF 755 /* Portability: Not all implementations of snprintf() 756 are ISO C 99 compliant. Determine the number of 757 bytes that snprintf() has produced or would have 758 produced. */ 759 if (count >= 0) 760 { 761 /* Verify that snprintf() has NUL-terminated its 762 result. */ 763 if (count < maxlen && result[length + count] != '\0') 764 abort (); 765 /* Portability hack. */ 766 if (retcount > count) 767 count = retcount; 768 } 769 else 770 { 771 /* snprintf() doesn't understand the '%n' 772 directive. */ 773 if (p[1] != '\0') 774 { 775 /* Don't use the '%n' directive; instead, look 776 at the snprintf() return value. */ 777 p[1] = '\0'; 778 continue; 779 } 780 else 781 { 782 /* Look at the snprintf() return value. */ 783 if (retcount < 0) 784 { 785 /* HP-UX 10.20 snprintf() is doubly deficient: 786 It doesn't understand the '%n' directive, 787 *and* it returns -1 (rather than the length 788 that would have been required) when the 789 buffer is too small. */ 790 size_t bigger_need = 791 xsum (xtimes (allocated, 2), 12); 792 ENSURE_ALLOCATION (bigger_need); 793 continue; 794 } 795 else 796 count = retcount; 797 } 798 } 799 #endif 800 801 /* Attempt to handle failure. */ 802 if (count < 0) 803 { 804 if (!(result == resultbuf || result == NULL)) 805 free (result); 806 if (buf_malloced != NULL) 807 free (buf_malloced); 808 CLEANUP (); 809 errno = EINVAL; 810 return NULL; 811 } 812 813 #if !USE_SNPRINTF 814 if (count >= tmp_length) 815 /* tmp_length was incorrectly calculated - fix the 816 code above! */ 817 abort (); 818 #endif 819 820 /* Make room for the result. */ 821 if (count >= maxlen) 822 { 823 /* Need at least count bytes. But allocate 824 proportionally, to avoid looping eternally if 825 snprintf() reports a too small count. */ 826 size_t n = 827 xmax (xsum (length, count), xtimes (allocated, 2)); 828 829 ENSURE_ALLOCATION (n); 830 #if USE_SNPRINTF 831 continue; 832 #endif 833 } 834 835 #if USE_SNPRINTF 836 /* The snprintf() result did fit. */ 837 #else 838 /* Append the sprintf() result. */ 839 memcpy (result + length, tmp, count * sizeof (CHAR_T)); 840 if (tmp != tmpbuf) 841 free (tmp); 842 #endif 843 844 length += count; 845 break; 846 } 847 } 848 } 849 } 850 851 /* Add the final NUL. */ 852 ENSURE_ALLOCATION (xsum (length, 1)); 853 result[length] = '\0'; 854 855 if (result != resultbuf && length + 1 < allocated) 856 { 857 /* Shrink the allocated memory if possible. */ 858 CHAR_T *memory; 859 860 memory = (CHAR_T *) realloc (result, (length + 1) * sizeof (CHAR_T)); 861 if (memory != NULL) 862 result = memory; 863 } 864 865 if (buf_malloced != NULL) 866 free (buf_malloced); 867 CLEANUP (); 868 *lengthp = length; 869 return result; 870 871 out_of_memory: 872 if (!(result == resultbuf || result == NULL)) 873 free (result); 874 if (buf_malloced != NULL) 875 free (buf_malloced); 876 out_of_memory_1: 877 CLEANUP (); 878 errno = ENOMEM; 879 return NULL; 880 } 881 } 882 883 #undef SNPRINTF 884 #undef USE_SNPRINTF 885 #undef PRINTF_PARSE 886 #undef DIRECTIVES 887 #undef DIRECTIVE 888 #undef CHAR_T 889 #undef VASNPRINTF 890