No empty .Rs/.Re
[netbsd-mini2440.git] / gnu / dist / texinfo / intl / vasnprintf.c
blob8e6f36653eceda7c98f2401caf2ef462c713f3e3
1 /* $NetBSD$ */
3 /* vsprintf with automatic memory allocation.
4 Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc.
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.
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.
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. */
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
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
31 #ifndef IN_LIBINTL
32 # include <alloca.h>
33 #endif
35 /* Specification. */
36 #if WIDE_CHAR_VERSION
37 # include "vasnwprintf.h"
38 #else
39 # include "vasnprintf.h"
40 #endif
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
54 /* Checked size_t computations. */
55 #include "xsize.h"
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)
70 const wchar_t *ptr;
72 for (ptr = s; *ptr != (wchar_t) 0; ptr++)
74 return ptr - s;
76 # endif
77 # endif
78 #endif
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
111 CHAR_T *
112 VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args)
114 DIRECTIVES d;
115 arguments a;
117 if (PRINTF_PARSE (format, &d, &a) < 0)
119 errno = EINVAL;
120 return NULL;
123 #define CLEANUP() \
124 free (d.dir); \
125 if (a.arg) \
126 free (a.arg);
128 if (printf_fetchargs (args, &a) < 0)
130 CLEANUP ();
131 errno = EINVAL;
132 return NULL;
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;
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))
154 buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T));
155 buf_malloced = NULL;
157 else
158 #endif
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;
169 if (resultbuf != NULL)
171 result = resultbuf;
172 allocated = *lengthp;
174 else
176 result = NULL;
177 allocated = 0;
179 length = 0;
180 /* Invariants:
181 result is either == resultbuf or == NULL or malloc-allocated.
182 If length > 0, then result != NULL. */
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) \
189 size_t memory_size; \
190 CHAR_T *memory; \
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; \
209 for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++)
211 if (cp != dp->dir_start)
213 size_t n = dp->dir_start - cp;
214 size_t augmented_length = xsum (length, n);
216 ENSURE_ALLOCATION (augmented_length);
217 memcpy (result + length, cp, n * sizeof (CHAR_T));
218 length = augmented_length;
220 if (i == d.count)
221 break;
223 /* Execute a single directive. */
224 if (dp->conversion == '%')
226 size_t augmented_length;
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;
235 else
237 if (!(dp->arg_index != ARG_NONE))
238 abort ();
240 if (dp->conversion == 'n')
242 switch (a.arg[dp->arg_index].type)
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 ();
265 else
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;
276 /* Allocate a temporary buffer of sufficient size for calling
277 sprintf. */
279 size_t width;
280 size_t precision;
282 width = 0;
283 if (dp->width_start != dp->width_end)
285 if (dp->width_arg_index != ARG_NONE)
287 int arg;
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);
294 else
296 const CHAR_T *digitp = dp->width_start;
299 width = xsum (xtimes (width, 10), *digitp++ - '0');
300 while (digitp != dp->width_end);
304 precision = 6;
305 if (dp->precision_start != dp->precision_end)
307 if (dp->precision_arg_index != ARG_NONE)
309 int arg;
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);
316 else
318 const CHAR_T *digitp = dp->precision_start + 1;
320 precision = 0;
322 precision = xsum (xtimes (precision, 10), *digitp++ - '0');
323 while (digitp != dp->precision_end);
327 switch (dp->conversion)
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 */
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 */
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 */
356 + 1 /* turn floor into ceil */
357 + 1; /* account for leading sign */
358 break;
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 */
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 */
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 */
383 + 1 /* turn floor into ceil */
384 + 1; /* account for leading sign */
385 break;
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 */
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 */
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 */
410 + 1 /* turn floor into ceil */
411 + 2; /* account for leading sign or alternate form */
412 break;
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 */
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 */
431 + 1 /* turn floor into ceil */
432 + 10; /* sign, decimal point etc. */
433 tmp_length = xsum (tmp_length, precision);
434 break;
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;
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;
452 case 's':
453 # ifdef HAVE_WCHAR_T
454 if (type == TYPE_WIDE_STRING)
456 tmp_length =
457 local_wcslen (a.arg[dp->arg_index].a.a_wide_string);
459 # if !WIDE_CHAR_VERSION
460 tmp_length = xtimes (tmp_length, MB_CUR_MAX);
461 # endif
463 else
464 # endif
465 tmp_length = strlen (a.arg[dp->arg_index].a.a_string);
466 break;
468 case 'p':
469 tmp_length =
470 (unsigned int) (sizeof (void *) * CHAR_BIT
471 * 0.25 /* binary -> hexadecimal */
473 + 1 /* turn floor into ceil */
474 + 2; /* account for leading 0x */
475 break;
477 default:
478 abort ();
481 if (tmp_length < width)
482 tmp_length = width;
484 tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
487 if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T))
488 tmp = tmpbuf;
489 else
491 size_t tmp_memsize = xtimes (tmp_length, sizeof (CHAR_T));
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;
501 #endif
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)
521 size_t n = dp->width_end - dp->width_start;
522 memcpy (p, dp->width_start, n * sizeof (CHAR_T));
523 p += n;
525 if (dp->precision_start != dp->precision_end)
527 size_t n = dp->precision_end - dp->precision_start;
528 memcpy (p, dp->precision_start, n * sizeof (CHAR_T));
529 p += n;
532 switch (type)
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;
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
567 /* Construct the arguments for calling snprintf or sprintf. */
568 prefix_count = 0;
569 if (dp->width_arg_index != ARG_NONE)
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;
575 if (dp->precision_arg_index != ARG_NONE)
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;
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
589 for (;;)
591 size_t maxlen;
592 int count;
593 int retcount;
595 maxlen = allocated - length;
596 count = -1;
597 retcount = 0;
599 #if USE_SNPRINTF
600 # define SNPRINTF_BUF(arg) \
601 switch (prefix_count) \
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 (); \
619 #else
620 # define SNPRINTF_BUF(arg) \
621 switch (prefix_count) \
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 (); \
636 #endif
638 switch (type)
640 case TYPE_SCHAR:
642 int arg = a.arg[dp->arg_index].a.a_schar;
643 SNPRINTF_BUF (arg);
645 break;
646 case TYPE_UCHAR:
648 unsigned int arg = a.arg[dp->arg_index].a.a_uchar;
649 SNPRINTF_BUF (arg);
651 break;
652 case TYPE_SHORT:
654 int arg = a.arg[dp->arg_index].a.a_short;
655 SNPRINTF_BUF (arg);
657 break;
658 case TYPE_USHORT:
660 unsigned int arg = a.arg[dp->arg_index].a.a_ushort;
661 SNPRINTF_BUF (arg);
663 break;
664 case TYPE_INT:
666 int arg = a.arg[dp->arg_index].a.a_int;
667 SNPRINTF_BUF (arg);
669 break;
670 case TYPE_UINT:
672 unsigned int arg = a.arg[dp->arg_index].a.a_uint;
673 SNPRINTF_BUF (arg);
675 break;
676 case TYPE_LONGINT:
678 long int arg = a.arg[dp->arg_index].a.a_longint;
679 SNPRINTF_BUF (arg);
681 break;
682 case TYPE_ULONGINT:
684 unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint;
685 SNPRINTF_BUF (arg);
687 break;
688 #ifdef HAVE_LONG_LONG
689 case TYPE_LONGLONGINT:
691 long long int arg = a.arg[dp->arg_index].a.a_longlongint;
692 SNPRINTF_BUF (arg);
694 break;
695 case TYPE_ULONGLONGINT:
697 unsigned long long int arg = a.arg[dp->arg_index].a.a_ulonglongint;
698 SNPRINTF_BUF (arg);
700 break;
701 #endif
702 case TYPE_DOUBLE:
704 double arg = a.arg[dp->arg_index].a.a_double;
705 SNPRINTF_BUF (arg);
707 break;
708 #ifdef HAVE_LONG_DOUBLE
709 case TYPE_LONGDOUBLE:
711 long double arg = a.arg[dp->arg_index].a.a_longdouble;
712 SNPRINTF_BUF (arg);
714 break;
715 #endif
716 case TYPE_CHAR:
718 int arg = a.arg[dp->arg_index].a.a_char;
719 SNPRINTF_BUF (arg);
721 break;
722 #ifdef HAVE_WINT_T
723 case TYPE_WIDE_CHAR:
725 wint_t arg = a.arg[dp->arg_index].a.a_wide_char;
726 SNPRINTF_BUF (arg);
728 break;
729 #endif
730 case TYPE_STRING:
732 const char *arg = a.arg[dp->arg_index].a.a_string;
733 SNPRINTF_BUF (arg);
735 break;
736 #ifdef HAVE_WCHAR_T
737 case TYPE_WIDE_STRING:
739 const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string;
740 SNPRINTF_BUF (arg);
742 break;
743 #endif
744 case TYPE_POINTER:
746 void *arg = a.arg[dp->arg_index].a.a_pointer;
747 SNPRINTF_BUF (arg);
749 break;
750 default:
751 abort ();
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)
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;
769 else
771 /* snprintf() doesn't understand the '%n'
772 directive. */
773 if (p[1] != '\0')
775 /* Don't use the '%n' directive; instead, look
776 at the snprintf() return value. */
777 p[1] = '\0';
778 continue;
780 else
782 /* Look at the snprintf() return value. */
783 if (retcount < 0)
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;
795 else
796 count = retcount;
799 #endif
801 /* Attempt to handle failure. */
802 if (count < 0)
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;
813 #if !USE_SNPRINTF
814 if (count >= tmp_length)
815 /* tmp_length was incorrectly calculated - fix the
816 code above! */
817 abort ();
818 #endif
820 /* Make room for the result. */
821 if (count >= maxlen)
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));
829 ENSURE_ALLOCATION (n);
830 #if USE_SNPRINTF
831 continue;
832 #endif
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
844 length += count;
845 break;
851 /* Add the final NUL. */
852 ENSURE_ALLOCATION (xsum (length, 1));
853 result[length] = '\0';
855 if (result != resultbuf && length + 1 < allocated)
857 /* Shrink the allocated memory if possible. */
858 CHAR_T *memory;
860 memory = (CHAR_T *) realloc (result, (length + 1) * sizeof (CHAR_T));
861 if (memory != NULL)
862 result = memory;
865 if (buf_malloced != NULL)
866 free (buf_malloced);
867 CLEANUP ();
868 *lengthp = length;
869 return result;
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;
883 #undef SNPRINTF
884 #undef USE_SNPRINTF
885 #undef PRINTF_PARSE
886 #undef DIRECTIVES
887 #undef DIRECTIVE
888 #undef CHAR_T
889 #undef VASNPRINTF