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