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