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 #include <sys/cdefs.h>
18 __RCSID("$NetBSD: vasnprintf.c,v 1.4 2016/05/17 14:00:09 christos Exp $");
19 
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 #ifdef __SSP__
32 #undef HAVE_ALLOCA
33 #endif
34 #ifndef __NetBSD__
35 #ifndef IN_LIBINTL
36 # include <alloca.h>
37 #endif
38 #endif
39 
40 /* Specification.  */
41 #if WIDE_CHAR_VERSION
42 # include "vasnwprintf.h"
43 #else
44 # include "vasnprintf.h"
45 #endif
46 
47 #include <stdio.h>  /* snprintf(), sprintf() */
48 #include <stdlib.h> /* abort(), malloc(), realloc(), free() */
49 #include <string.h> /* memcpy(), strlen() */
50 #include <errno.h>  /* errno */
51 #include <limits.h> /* CHAR_BIT, INT_MAX */
52 #include <float.h>  /* DBL_MAX_EXP, LDBL_MAX_EXP */
53 #if WIDE_CHAR_VERSION
54 # include "wprintf-parse.h"
55 #else
56 # include "printf-parse.h"
57 #endif
58 
59 /* Checked size_t computations.  */
60 #include "xsize.h"
61 
62 /* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW.  */
63 #ifndef EOVERFLOW
64 # define EOVERFLOW E2BIG
65 #endif
66 
67 #ifdef HAVE_WCHAR_T
68 # ifdef HAVE_WCSLEN
69 #  define local_wcslen wcslen
70 # else
71    /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid
72       a dependency towards this library, here is a local substitute.
73       Define this substitute only once, even if this file is included
74       twice in the same compilation unit.  */
75 #  ifndef local_wcslen_defined
76 #   define local_wcslen_defined 1
77 static size_t
local_wcslen(const wchar_t * s)78 local_wcslen (const wchar_t *s)
79 {
80   const wchar_t *ptr;
81 
82   for (ptr = s; *ptr != (wchar_t) 0; ptr++)
83     ;
84   return ptr - s;
85 }
86 #  endif
87 # endif
88 #endif
89 
90 #if WIDE_CHAR_VERSION
91 # define VASNPRINTF vasnwprintf
92 # define CHAR_T wchar_t
93 # define DIRECTIVE wchar_t_directive
94 # define DIRECTIVES wchar_t_directives
95 # define PRINTF_PARSE wprintf_parse
96 # define USE_SNPRINTF 1
97 # if HAVE_DECL__SNWPRINTF
98    /* On Windows, the function swprintf() has a different signature than
99       on Unix; we use the _snwprintf() function instead.  */
100 #  define SNPRINTF _snwprintf
101 # else
102    /* Unix.  */
103 #  define SNPRINTF swprintf
104 # endif
105 #else
106 # define VASNPRINTF vasnprintf
107 # define CHAR_T char
108 # define DIRECTIVE char_directive
109 # define DIRECTIVES char_directives
110 # define PRINTF_PARSE printf_parse
111 # define USE_SNPRINTF (HAVE_DECL__SNPRINTF || HAVE_SNPRINTF)
112 # if HAVE_DECL__SNPRINTF
113    /* Windows.  */
114 #  define SNPRINTF _snprintf
115 # else
116    /* Unix.  */
117 #  define SNPRINTF snprintf
118 # endif
119 #endif
120 
121 CHAR_T *
VASNPRINTF(CHAR_T * resultbuf,size_t * lengthp,const CHAR_T * format,va_list args)122 VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args)
123 {
124   DIRECTIVES d;
125   arguments a;
126 
127   if (PRINTF_PARSE (format, &d, &a) < 0)
128     {
129       errno = EINVAL;
130       return NULL;
131     }
132 
133 #define CLEANUP() \
134   free (d.dir);                                                                           \
135   if (a.arg)                                                                              \
136     free (a.arg);
137 
138   if (printf_fetchargs (args, &a) < 0)
139     {
140       CLEANUP ();
141       errno = EINVAL;
142       return NULL;
143     }
144 
145   {
146     size_t buf_neededlength;
147     CHAR_T *buf;
148     CHAR_T *buf_malloced;
149     const CHAR_T *cp;
150     size_t i;
151     DIRECTIVE *dp;
152     /* Output string accumulator.  */
153     CHAR_T *result;
154     size_t allocated;
155     size_t length;
156 
157     /* Allocate a small buffer that will hold a directive passed to
158        sprintf or snprintf.  */
159     buf_neededlength =
160       xsum4 (7, d.max_width_length, d.max_precision_length, 6);
161 #if HAVE_ALLOCA
162     if (buf_neededlength < 4000 / sizeof (CHAR_T))
163       {
164           buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T));
165           buf_malloced = NULL;
166       }
167     else
168 #endif
169       {
170           size_t buf_memsize = xtimes (buf_neededlength, sizeof (CHAR_T));
171           if (size_overflow_p (buf_memsize))
172             goto out_of_memory_1;
173           buf = (CHAR_T *) malloc (buf_memsize);
174           if (buf == NULL)
175             goto out_of_memory_1;
176           buf_malloced = buf;
177       }
178 
179     if (resultbuf != NULL)
180       {
181           result = resultbuf;
182           allocated = *lengthp;
183       }
184     else
185       {
186           result = NULL;
187           allocated = 0;
188       }
189     length = 0;
190     /* Invariants:
191        result is either == resultbuf or == NULL or malloc-allocated.
192        If length > 0, then result != NULL.  */
193 
194     /* Ensures that allocated >= needed.  Aborts through a jump to
195        out_of_memory if needed is SIZE_MAX or otherwise too big.  */
196 #define ENSURE_ALLOCATION(needed) \
197     if ((needed) > allocated)                                                        \
198       {                                                                                        \
199           size_t memory_size;                                                        \
200           CHAR_T *memory;                                                                      \
201                                                                                                \
202           allocated = (allocated > 0 ? xtimes (allocated, 2) : 12);        \
203           if ((needed) > allocated)                                                  \
204             allocated = (needed);                                                              \
205           memory_size = xtimes (allocated, sizeof (CHAR_T));                         \
206           if (size_overflow_p (memory_size))                                         \
207             goto out_of_memory;                                                                \
208           if (result == resultbuf || result == NULL)                                 \
209             memory = (CHAR_T *) malloc (memory_size);                                \
210           else                                                                                 \
211             memory = (CHAR_T *) realloc (result, memory_size);                       \
212           if (memory == NULL)                                                        \
213             goto out_of_memory;                                                                \
214           if (result == resultbuf && length > 0)                                     \
215             memcpy (memory, result, length * sizeof (CHAR_T));                       \
216           result = memory;                                                           \
217       }
218 
219     for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++)
220       {
221           if (cp != dp->dir_start)
222             {
223               size_t n = dp->dir_start - cp;
224               size_t augmented_length = xsum (length, n);
225 
226               ENSURE_ALLOCATION (augmented_length);
227               memcpy (result + length, cp, n * sizeof (CHAR_T));
228               length = augmented_length;
229             }
230           if (i == d.count)
231             break;
232 
233           /* Execute a single directive.  */
234           if (dp->conversion == '%')
235             {
236               size_t augmented_length;
237 
238               if (!(dp->arg_index == ARG_NONE))
239                 abort ();
240               augmented_length = xsum (length, 1);
241               ENSURE_ALLOCATION (augmented_length);
242               result[length] = '%';
243               length = augmented_length;
244             }
245           else
246             {
247               if (!(dp->arg_index != ARG_NONE))
248                 abort ();
249 
250               if (dp->conversion == 'n')
251                 {
252                     switch (a.arg[dp->arg_index].type)
253                       {
254                       case TYPE_COUNT_SCHAR_POINTER:
255                         *a.arg[dp->arg_index].a.a_count_schar_pointer = length;
256                         break;
257                       case TYPE_COUNT_SHORT_POINTER:
258                         *a.arg[dp->arg_index].a.a_count_short_pointer = length;
259                         break;
260                       case TYPE_COUNT_INT_POINTER:
261                         *a.arg[dp->arg_index].a.a_count_int_pointer = length;
262                         break;
263                       case TYPE_COUNT_LONGINT_POINTER:
264                         *a.arg[dp->arg_index].a.a_count_longint_pointer = length;
265                         break;
266 #ifdef HAVE_LONG_LONG
267                       case TYPE_COUNT_LONGLONGINT_POINTER:
268                         *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
269                         break;
270 #endif
271                       default:
272                         abort ();
273                       }
274                 }
275               else
276                 {
277                     arg_type type = a.arg[dp->arg_index].type;
278                     CHAR_T *p;
279                     unsigned int prefix_count;
280                     int prefixes[2];
281 #if !USE_SNPRINTF
282                     size_t tmp_length;
283                     CHAR_T tmpbuf[700];
284                     CHAR_T *tmp;
285 
286                     /* Allocate a temporary buffer of sufficient size for calling
287                        sprintf.  */
288                     {
289                       size_t width;
290                       size_t precision;
291 
292                       width = 0;
293                       if (dp->width_start != dp->width_end)
294                         {
295                           if (dp->width_arg_index != ARG_NONE)
296                               {
297                                 int arg;
298 
299                                 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
300                                   abort ();
301                                 arg = a.arg[dp->width_arg_index].a.a_int;
302                                 width = (arg < 0 ? (unsigned int) (-arg) : arg);
303                               }
304                           else
305                               {
306                                 const CHAR_T *digitp = dp->width_start;
307 
308                                 do
309                                   width = xsum (xtimes (width, 10), *digitp++ - '0');
310                                 while (digitp != dp->width_end);
311                               }
312                         }
313 
314                       precision = 6;
315                       if (dp->precision_start != dp->precision_end)
316                         {
317                           if (dp->precision_arg_index != ARG_NONE)
318                               {
319                                 int arg;
320 
321                                 if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
322                                   abort ();
323                                 arg = a.arg[dp->precision_arg_index].a.a_int;
324                                 precision = (arg < 0 ? 0 : arg);
325                               }
326                           else
327                               {
328                                 const CHAR_T *digitp = dp->precision_start + 1;
329 
330                                 precision = 0;
331                                 while (digitp != dp->precision_end)
332                                   precision = xsum (xtimes (precision, 10), *digitp++ - '0');
333                               }
334                         }
335 
336                       switch (dp->conversion)
337                         {
338 
339                         case 'd': case 'i': case 'u':
340 # ifdef HAVE_LONG_LONG
341                           if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
342                               tmp_length =
343                                 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
344                                                     * 0.30103 /* binary -> decimal */
345                                                     * 2 /* estimate for FLAG_GROUP */
346                                                    )
347                                 + 1 /* turn floor into ceil */
348                                 + 1; /* account for leading sign */
349                           else
350 # endif
351                           if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
352                               tmp_length =
353                                 (unsigned int) (sizeof (unsigned long) * CHAR_BIT
354                                                     * 0.30103 /* binary -> decimal */
355                                                     * 2 /* estimate for FLAG_GROUP */
356                                                    )
357                                 + 1 /* turn floor into ceil */
358                                 + 1; /* account for leading sign */
359                           else
360                               tmp_length =
361                                 (unsigned int) (sizeof (unsigned int) * CHAR_BIT
362                                                     * 0.30103 /* binary -> decimal */
363                                                     * 2 /* estimate for FLAG_GROUP */
364                                                    )
365                                 + 1 /* turn floor into ceil */
366                                 + 1; /* account for leading sign */
367                           break;
368 
369                         case 'o':
370 # ifdef HAVE_LONG_LONG
371                           if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
372                               tmp_length =
373                                 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
374                                                     * 0.333334 /* binary -> octal */
375                                                    )
376                                 + 1 /* turn floor into ceil */
377                                 + 1; /* account for leading sign */
378                           else
379 # endif
380                           if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
381                               tmp_length =
382                                 (unsigned int) (sizeof (unsigned long) * CHAR_BIT
383                                                     * 0.333334 /* binary -> octal */
384                                                    )
385                                 + 1 /* turn floor into ceil */
386                                 + 1; /* account for leading sign */
387                           else
388                               tmp_length =
389                                 (unsigned int) (sizeof (unsigned int) * CHAR_BIT
390                                                     * 0.333334 /* binary -> octal */
391                                                    )
392                                 + 1 /* turn floor into ceil */
393                                 + 1; /* account for leading sign */
394                           break;
395 
396                         case 'x': case 'X':
397 # ifdef HAVE_LONG_LONG
398                           if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
399                               tmp_length =
400                                 (unsigned int) (sizeof (unsigned long 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 # endif
407                           if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
408                               tmp_length =
409                                 (unsigned int) (sizeof (unsigned long) * CHAR_BIT
410                                                     * 0.25 /* binary -> hexadecimal */
411                                                    )
412                                 + 1 /* turn floor into ceil */
413                                 + 2; /* account for leading sign or alternate form */
414                           else
415                               tmp_length =
416                                 (unsigned int) (sizeof (unsigned int) * CHAR_BIT
417                                                     * 0.25 /* binary -> hexadecimal */
418                                                    )
419                                 + 1 /* turn floor into ceil */
420                                 + 2; /* account for leading sign or alternate form */
421                           break;
422 
423                         case 'f': case 'F':
424 # ifdef HAVE_LONG_DOUBLE
425                           if (type == TYPE_LONGDOUBLE)
426                               tmp_length =
427                                 (unsigned int) (LDBL_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                           else
434 # endif
435                               tmp_length =
436                                 (unsigned int) (DBL_MAX_EXP
437                                                     * 0.30103 /* binary -> decimal */
438                                                     * 2 /* estimate for FLAG_GROUP */
439                                                    )
440                                 + 1 /* turn floor into ceil */
441                                 + 10; /* sign, decimal point etc. */
442                           tmp_length = xsum (tmp_length, precision);
443                           break;
444 
445                         case 'e': case 'E': case 'g': case 'G':
446                         case 'a': case 'A':
447                           tmp_length =
448                               12; /* sign, decimal point, exponent etc. */
449                           tmp_length = xsum (tmp_length, precision);
450                           break;
451 
452                         case 'c':
453 # if defined HAVE_WINT_T && !WIDE_CHAR_VERSION
454                           if (type == TYPE_WIDE_CHAR)
455                               tmp_length = MB_CUR_MAX;
456                           else
457 # endif
458                               tmp_length = 1;
459                           break;
460 
461                         case 's':
462 # ifdef HAVE_WCHAR_T
463                           if (type == TYPE_WIDE_STRING)
464                               {
465                                 tmp_length =
466                                   local_wcslen (a.arg[dp->arg_index].a.a_wide_string);
467 
468 #  if !WIDE_CHAR_VERSION
469                                 tmp_length = xtimes (tmp_length, MB_CUR_MAX);
470 #  endif
471                               }
472                           else
473 # endif
474                               tmp_length = strlen (a.arg[dp->arg_index].a.a_string);
475                           break;
476 
477                         case 'p':
478                           tmp_length =
479                               (unsigned int) (sizeof (void *) * CHAR_BIT
480                                                   * 0.25 /* binary -> hexadecimal */
481                                                )
482                                 + 1 /* turn floor into ceil */
483                                 + 2; /* account for leading 0x */
484                           break;
485 
486                         default:
487                           abort ();
488                         }
489 
490                       if (tmp_length < width)
491                         tmp_length = width;
492 
493                       tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
494                     }
495 
496                     if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T))
497                       tmp = tmpbuf;
498                     else
499                       {
500                         size_t tmp_memsize = xtimes (tmp_length, sizeof (CHAR_T));
501 
502                         if (size_overflow_p (tmp_memsize))
503                           /* Overflow, would lead to out of memory.  */
504                           goto out_of_memory;
505                         tmp = (CHAR_T *) malloc (tmp_memsize);
506                         if (tmp == NULL)
507                           /* Out of memory.  */
508                           goto out_of_memory;
509                       }
510 #endif
511 
512                     /* Construct the format string for calling snprintf or
513                        sprintf.  */
514                     p = buf;
515                     *p++ = '%';
516                     if (dp->flags & FLAG_GROUP)
517                       *p++ = '\'';
518                     if (dp->flags & FLAG_LEFT)
519                       *p++ = '-';
520                     if (dp->flags & FLAG_SHOWSIGN)
521                       *p++ = '+';
522                     if (dp->flags & FLAG_SPACE)
523                       *p++ = ' ';
524                     if (dp->flags & FLAG_ALT)
525                       *p++ = '#';
526                     if (dp->flags & FLAG_ZERO)
527                       *p++ = '0';
528                     if (dp->width_start != dp->width_end)
529                       {
530                         size_t n = dp->width_end - dp->width_start;
531                         memcpy (p, dp->width_start, n * sizeof (CHAR_T));
532                         p += n;
533                       }
534                     if (dp->precision_start != dp->precision_end)
535                       {
536                         size_t n = dp->precision_end - dp->precision_start;
537                         memcpy (p, dp->precision_start, n * sizeof (CHAR_T));
538                         p += n;
539                       }
540 
541                     switch (type)
542                       {
543 #ifdef HAVE_LONG_LONG
544                       case TYPE_LONGLONGINT:
545                       case TYPE_ULONGLONGINT:
546                         *p++ = 'l';
547                         /*FALLTHROUGH*/
548 #endif
549                       case TYPE_LONGINT:
550                       case TYPE_ULONGINT:
551 #ifdef HAVE_WINT_T
552                       case TYPE_WIDE_CHAR:
553 #endif
554 #ifdef HAVE_WCHAR_T
555                       case TYPE_WIDE_STRING:
556 #endif
557                         *p++ = 'l';
558                         break;
559 #ifdef HAVE_LONG_DOUBLE
560                       case TYPE_LONGDOUBLE:
561                         *p++ = 'L';
562                         break;
563 #endif
564                       default:
565                         break;
566                       }
567                     *p = dp->conversion;
568                     p[1] = '\0';
569 
570                     /* Construct the arguments for calling snprintf or sprintf.  */
571                     prefix_count = 0;
572                     if (dp->width_arg_index != ARG_NONE)
573                       {
574                         if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
575                           abort ();
576                         prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int;
577                       }
578                     if (dp->precision_arg_index != ARG_NONE)
579                       {
580                         if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
581                           abort ();
582                         prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int;
583                       }
584 
585 #if USE_SNPRINTF
586                     /* Prepare checking whether snprintf returns the count
587                        via %n.  */
588                     ENSURE_ALLOCATION (xsum (length, 1));
589                     result[length] = '\0';
590 #endif
591 
592                     for (;;)
593                       {
594                         size_t maxlen;
595                         int count;
596 
597                         maxlen = allocated - length;
598                         count = -1;
599 
600 #if USE_SNPRINTF
601 # define SNPRINTF_BUF(arg) \
602                         switch (prefix_count)                                       \
603                           {                                                                   \
604                           case 0:                                                             \
605                               count = SNPRINTF (result + length, maxlen, buf,     \
606                                                        arg);                                  \
607                               break;                                                          \
608                           case 1:                                                             \
609                               count = SNPRINTF (result + length, maxlen, buf,     \
610                                                        prefixes[0], arg);                   \
611                               break;                                                          \
612                           case 2:                                                             \
613                               count = SNPRINTF (result + length, maxlen, buf,     \
614                                                     prefixes[0], prefixes[1], arg);   \
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                           }
766 #endif
767 
768                         /* Attempt to handle failure.  */
769                         if (count < 0)
770                           {
771                               if (!(result == resultbuf || result == NULL))
772                                 free (result);
773                               if (buf_malloced != NULL)
774                                 free (buf_malloced);
775                               CLEANUP ();
776                               errno = EINVAL;
777                               return NULL;
778                           }
779 
780 #if !USE_SNPRINTF
781                         if (count >= tmp_length)
782                           /* tmp_length was incorrectly calculated - fix the
783                                code above!  */
784                           abort ();
785 #endif
786 
787                         /* Make room for the result.  */
788                         if (count >= maxlen)
789                           {
790                               /* Need at least count bytes.  But allocate
791                                  proportionally, to avoid looping eternally if
792                                  snprintf() reports a too small count.  */
793                               size_t n =
794                                 xmax (xsum (length, count), xtimes (allocated, 2));
795 
796                               ENSURE_ALLOCATION (n);
797 #if USE_SNPRINTF
798                               continue;
799 #endif
800                           }
801 
802 #if USE_SNPRINTF
803                         /* The snprintf() result did fit.  */
804 #else
805                         /* Append the sprintf() result.  */
806                         memcpy (result + length, tmp, count * sizeof (CHAR_T));
807                         if (tmp != tmpbuf)
808                           free (tmp);
809 #endif
810 
811                         length += count;
812                         break;
813                       }
814                 }
815             }
816       }
817 
818     /* Add the final NUL.  */
819     ENSURE_ALLOCATION (xsum (length, 1));
820     result[length] = '\0';
821 
822     if (result != resultbuf && length + 1 < allocated)
823       {
824           /* Shrink the allocated memory if possible.  */
825           CHAR_T *memory;
826 
827           memory = (CHAR_T *) realloc (result, (length + 1) * sizeof (CHAR_T));
828           if (memory != NULL)
829             result = memory;
830       }
831 
832     if (buf_malloced != NULL)
833       free (buf_malloced);
834     CLEANUP ();
835     *lengthp = length;
836     if (length > INT_MAX)
837       goto length_overflow;
838     return result;
839 
840   length_overflow:
841     /* We could produce such a big string, but its length doesn't fit into
842        an 'int'.  POSIX says that snprintf() fails with errno = EOVERFLOW in
843        this case.  */
844     if (result != resultbuf)
845       free (result);
846     errno = EOVERFLOW;
847     return NULL;
848 
849   out_of_memory:
850     if (!(result == resultbuf || result == NULL))
851       free (result);
852     if (buf_malloced != NULL)
853       free (buf_malloced);
854   out_of_memory_1:
855     CLEANUP ();
856     errno = ENOMEM;
857     return NULL;
858   }
859 }
860 
861 #undef SNPRINTF
862 #undef USE_SNPRINTF
863 #undef PRINTF_PARSE
864 #undef DIRECTIVES
865 #undef DIRECTIVE
866 #undef CHAR_T
867 #undef VASNPRINTF
868