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