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