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