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