f20d3bc70313089f1917852d37bd7c9fa68c3a01
[platform/upstream/gstreamer.git] / gst / printf / 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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17    USA.  */
18
19 #ifndef _WIN32
20 /* Tell glibc's <stdio.h> to provide a prototype for snprintf().
21    This must come before <config.h> because <config.h> may include
22    <features.h>, and once <features.h> has been included, it's too late.  */
23 #ifndef _GNU_SOURCE
24 # define _GNU_SOURCE    1
25 #endif
26 #endif
27
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
31
32 #include "gst-printf.h"
33
34 /* Specification.  */
35 #include "vasnprintf.h"
36
37 #include <stdio.h>              /* snprintf(), sprintf() */
38 #include <stdlib.h>             /* abort(), malloc(), realloc(), free() */
39 #include <string.h>             /* memcpy(), strlen() */
40 #include <errno.h>              /* errno */
41 #include <limits.h>             /* CHAR_BIT */
42 #include <float.h>              /* DBL_MAX_EXP, LDBL_MAX_EXP */
43 #include "printf-parse.h"
44 #include "printf-extension.h"
45
46 #ifdef HAVE_WCHAR_T
47 # ifdef HAVE_WCSLEN
48 #  define local_wcslen wcslen
49 # else
50    /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid
51       a dependency towards this library, here is a local substitute.
52       Define this substitute only once, even if this file is included
53       twice in the same compilation unit.  */
54 #  ifndef local_wcslen_defined
55 #   define local_wcslen_defined 1
56 static size_t
57 local_wcslen (const wchar_t * s)
58 {
59   const wchar_t *ptr;
60
61   for (ptr = s; *ptr != (wchar_t) 0; ptr++);
62   return ptr - s;
63 }
64 #  endif
65 # endif
66 #endif
67
68 /* For those losing systems which don't have 'alloca' we have to add
69    some additional code emulating it.  */
70 #ifdef GLIB_HAVE_ALLOCA_H
71 # define freea(p)               /* nothing */
72 #else
73 # define alloca(n) malloc (n)
74 # define freea(p) free (p)
75 #endif
76
77 #ifndef HAVE_LONG_LONG_FORMAT
78 static int
79 print_long_long (char *buf,
80     int len,
81     int width,
82     int precision,
83     unsigned long flags, char conversion, unsigned long long number)
84 {
85   int negative = FALSE;
86   char buffer[128];
87   char *bufferend;
88   char *pointer;
89   int base;
90   static const char *upper = "0123456789ABCDEFX";
91   static const char *lower = "0123456789abcdefx";
92   const char *digits;
93   int i;
94   char *p;
95   int count;
96
97 #define EMIT(c)           \
98   if (p - buf == len - 1) \
99     {                     \
100       *p++ = '\0';        \
101       return len;         \
102     }                     \
103   else                    \
104     *p++ = c;
105
106   p = buf;
107
108   switch (conversion) {
109     case 'o':
110       base = 8;
111       digits = lower;
112       negative = FALSE;
113       break;
114     case 'x':
115       base = 16;
116       digits = lower;
117       negative = FALSE;
118       break;
119     case 'X':
120       base = 16;
121       digits = upper;
122       negative = FALSE;
123       break;
124     default:
125       base = 10;
126       digits = lower;
127       negative = (long long) number < 0;
128       if (negative)
129         number = -((long long) number);
130       break;
131   }
132
133   /* Build number */
134   pointer = bufferend = &buffer[sizeof (buffer) - 1];
135   *pointer-- = '\0';
136   for (i = 1; i < (int) sizeof (buffer); i++) {
137     *pointer-- = digits[number % base];
138     number /= base;
139     if (number == 0)
140       break;
141   }
142
143   /* Adjust width */
144   width -= (bufferend - pointer) - 1;
145
146   /* Adjust precision */
147   if (precision != -1) {
148     precision -= (bufferend - pointer) - 1;
149     if (precision < 0)
150       precision = 0;
151     flags |= FLAG_ZERO;
152   }
153
154   /* Adjust width further */
155   if (negative || (flags & FLAG_SHOWSIGN) || (flags & FLAG_SPACE))
156     width--;
157   if (flags & FLAG_ALT) {
158     switch (base) {
159       case 16:
160         width -= 2;
161         break;
162       case 8:
163         width--;
164         break;
165       default:
166         break;
167     }
168   }
169
170   /* Output prefixes spaces if needed */
171   if (!((flags & FLAG_LEFT) || ((flags & FLAG_ZERO) && (precision == -1)))) {
172     count = (precision == -1) ? 0 : precision;
173     while (width-- > count)
174       *p++ = ' ';
175   }
176
177   /* width has been adjusted for signs and alternatives */
178   if (negative) {
179     EMIT ('-');
180   } else if (flags & FLAG_SHOWSIGN) {
181     EMIT ('+');
182   } else if (flags & FLAG_SPACE) {
183     EMIT (' ');
184   }
185
186   if (flags & FLAG_ALT) {
187     switch (base) {
188       case 8:
189         EMIT ('0');
190         break;
191       case 16:
192         EMIT ('0');
193         EMIT (digits[16]);
194         break;
195       default:
196         break;
197     }                           /* switch base */
198   }
199
200   /* Output prefixed zero padding if needed */
201   if (flags & FLAG_ZERO) {
202     if (precision == -1)
203       precision = width;
204     while (precision-- > 0) {
205       EMIT ('0');
206       width--;
207     }
208   }
209
210   /* Output the number itself */
211   while (*(++pointer)) {
212     EMIT (*pointer);
213   }
214
215   /* Output trailing spaces if needed */
216   if (flags & FLAG_LEFT) {
217     while (width-- > 0)
218       EMIT (' ');
219   }
220
221   EMIT ('\0');
222
223   return p - buf - 1;
224 }
225 #endif
226
227 static void
228 printf_postprocess_args (char_directives * directives, arguments * arguments)
229 {
230   int i;
231
232   for (i = 0; i < directives->count; ++i) {
233     char_directive *dp;
234     argument *a;
235
236     dp = &directives->dir[i];
237     a = &arguments->arg[dp->arg_index];
238
239     if (a->type == TYPE_POINTER_EXT) {
240       char fmt[4];
241
242       fmt[0] = 'p';
243       fmt[1] = POINTER_EXT_SIGNIFIER_CHAR;
244       fmt[2] = dp->ptr_ext_char;
245       fmt[3] = '\0';
246
247       a->ext_string =
248           __gst_printf_pointer_extension_serialize (fmt, a->a.a_pointer);
249     }
250   }
251 }
252
253 char *
254 vasnprintf (char *resultbuf, size_t * lengthp, const char *format, va_list args)
255 {
256   char_directives d;
257   arguments a;
258
259   if (printf_parse (format, &d, &a) < 0) {
260     errno = EINVAL;
261     return NULL;
262   }
263 #define CLEANUP()                         \
264   free (d.dir);                           \
265   if (a.arg) {                            \
266     while (a.count--) {                   \
267       if (a.arg[a.count].ext_string)      \
268         free (a.arg[a.count].ext_string); \
269     }                                     \
270     free (a.arg);                         \
271   }
272
273   if (printf_fetchargs (args, &a) < 0) {
274     CLEANUP ();
275     errno = EINVAL;
276     return NULL;
277   }
278
279   /* collect TYPE_POINTER_EXT argument strings */
280   printf_postprocess_args (&d, &a);
281
282   {
283     char *buf =
284         (char *) alloca (7 + d.max_width_length + d.max_precision_length + 6);
285     const char *cp;
286     unsigned int i;
287     char_directive *dp;
288     /* Output string accumulator.  */
289     char *result;
290     size_t allocated;
291     size_t length;
292
293     if (resultbuf != NULL) {
294       result = resultbuf;
295       allocated = *lengthp;
296     } else {
297       result = NULL;
298       allocated = 0;
299     }
300     length = 0;
301     /* Invariants:
302        result is either == resultbuf or == NULL or malloc-allocated.
303        If length > 0, then result != NULL.  */
304
305 #define ENSURE_ALLOCATION(needed) \
306     if ((needed) > allocated)                                           \
307       {                                                                 \
308         char *memory;                                                   \
309                                                                         \
310         allocated = (allocated > 0 ? 2 * allocated : 12);               \
311         if ((needed) > allocated)                                       \
312           allocated = (needed);                                         \
313         if (result == resultbuf || result == NULL)                      \
314           memory = (char *) malloc (allocated);                         \
315         else                                                            \
316           memory = (char *) realloc (result, allocated);                \
317                                                                         \
318         if (memory == NULL)                                             \
319           {                                                             \
320             if (!(result == resultbuf || result == NULL))               \
321               free (result);                                            \
322             freea (buf);                                                \
323             CLEANUP ();                                                 \
324             errno = ENOMEM;                                             \
325             return NULL;                                                \
326           }                                                             \
327         if (result == resultbuf && length > 0)                          \
328           memcpy (memory, result, length);                              \
329         result = memory;                                                \
330       }
331
332     for (cp = format, i = 0, dp = &d.dir[0];; cp = dp->dir_end, i++, dp++) {
333       if (cp != dp->dir_start) {
334         size_t n = dp->dir_start - cp;
335
336         ENSURE_ALLOCATION (length + n);
337         memcpy (result + length, cp, n);
338         length += n;
339       }
340       if (i == d.count)
341         break;
342
343       /* Execute a single directive.  */
344       if (dp->conversion == '%') {
345         if (!(dp->arg_index < 0))
346           abort ();
347         ENSURE_ALLOCATION (length + 1);
348         result[length] = '%';
349         length += 1;
350       } else {
351         if (!(dp->arg_index >= 0))
352           abort ();
353
354         if (dp->conversion == 'n') {
355           switch (a.arg[dp->arg_index].type) {
356             case TYPE_COUNT_SCHAR_POINTER:
357               *a.arg[dp->arg_index].a.a_count_schar_pointer = length;
358               break;
359             case TYPE_COUNT_SHORT_POINTER:
360               *a.arg[dp->arg_index].a.a_count_short_pointer = length;
361               break;
362             case TYPE_COUNT_INT_POINTER:
363               *a.arg[dp->arg_index].a.a_count_int_pointer = length;
364               break;
365             case TYPE_COUNT_LONGINT_POINTER:
366               *a.arg[dp->arg_index].a.a_count_longint_pointer = length;
367               break;
368 #ifdef HAVE_LONG_LONG
369             case TYPE_COUNT_LONGLONGINT_POINTER:
370               *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
371               break;
372 #endif
373             default:
374               abort ();
375           }
376         } else {
377           arg_type type = a.arg[dp->arg_index].type;
378           char *p;
379           unsigned int prefix_count;
380           int prefixes[2];
381 #if !HAVE_SNPRINTF
382           unsigned int tmp_length;
383           char tmpbuf[700];
384           char *tmp;
385
386           /* Allocate a temporary buffer of sufficient size for calling
387              sprintf.  */
388           {
389             unsigned int width;
390             unsigned int precision;
391
392             width = 0;
393             if (dp->width_start != dp->width_end) {
394               if (dp->width_arg_index >= 0) {
395                 int arg;
396
397                 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
398                   abort ();
399                 arg = a.arg[dp->width_arg_index].a.a_int;
400                 width = (arg < 0 ? -arg : arg);
401               } else {
402                 const char *digitp = dp->width_start;
403
404                 do
405                   width = width * 10 + (*digitp++ - '0');
406                 while (digitp != dp->width_end);
407               }
408             }
409
410             precision = 6;
411             if (dp->precision_start != dp->precision_end) {
412               if (dp->precision_arg_index >= 0) {
413                 int arg;
414
415                 if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
416                   abort ();
417                 arg = a.arg[dp->precision_arg_index].a.a_int;
418                 precision = (arg < 0 ? 0 : arg);
419               } else {
420                 const char *digitp = dp->precision_start + 1;
421
422                 precision = 0;
423                 while (digitp != dp->precision_end)
424                   precision = precision * 10 + (*digitp++ - '0');
425               }
426             }
427
428             switch (dp->conversion) {
429               case 'd':
430               case 'i':
431               case 'u':
432 # ifdef HAVE_LONG_LONG
433                 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
434                   tmp_length = (unsigned int) (sizeof (unsigned long long) * CHAR_BIT * 0.30103 /* binary -> decimal */
435                       * 2       /* estimate for FLAG_GROUP */
436                       )
437                       + 1       /* turn floor into ceil */
438                       + 1;      /* account for leading sign */
439                 else
440 # endif
441                 if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
442                   tmp_length = (unsigned int) (sizeof (unsigned long) * CHAR_BIT * 0.30103      /* binary -> decimal */
443                       * 2       /* estimate for FLAG_GROUP */
444                       )
445                       + 1       /* turn floor into ceil */
446                       + 1;      /* account for leading sign */
447                 else
448                   tmp_length = (unsigned int) (sizeof (unsigned int) * CHAR_BIT * 0.30103       /* binary -> decimal */
449                       * 2       /* estimate for FLAG_GROUP */
450                       )
451                       + 1       /* turn floor into ceil */
452                       + 1;      /* account for leading sign */
453                 break;
454
455               case 'o':
456 # ifdef HAVE_LONG_LONG
457                 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
458                   tmp_length = (unsigned int) (sizeof (unsigned long long) * CHAR_BIT * 0.333334        /* binary -> octal */
459                       )
460                       + 1       /* turn floor into ceil */
461                       + 1;      /* account for leading sign */
462                 else
463 # endif
464                 if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
465                   tmp_length = (unsigned int) (sizeof (unsigned long) * CHAR_BIT * 0.333334     /* binary -> octal */
466                       )
467                       + 1       /* turn floor into ceil */
468                       + 1;      /* account for leading sign */
469                 else
470                   tmp_length = (unsigned int) (sizeof (unsigned int) * CHAR_BIT * 0.333334      /* binary -> octal */
471                       )
472                       + 1       /* turn floor into ceil */
473                       + 1;      /* account for leading sign */
474                 break;
475
476               case 'x':
477               case 'X':
478 # ifdef HAVE_LONG_LONG
479                 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
480                   tmp_length = (unsigned int) (sizeof (unsigned long long) * CHAR_BIT * 0.25    /* binary -> hexadecimal */
481                       )
482                       + 1       /* turn floor into ceil */
483                       + 2;      /* account for leading sign or alternate form */
484                 else
485 # endif
486 # ifdef HAVE_INT64_AND_I64
487                 if (type == TYPE_INT64 || type == TYPE_UINT64)
488                   tmp_length = (unsigned int) (sizeof (unsigned __int64) * CHAR_BIT * 0.25      /* binary -> hexadecimal */
489                       )
490                       + 1       /* turn floor into ceil */
491                       + 2;      /* account for leading sign or alternate form */
492                 else
493 # endif
494                 if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
495                   tmp_length = (unsigned int) (sizeof (unsigned long) * CHAR_BIT * 0.25 /* binary -> hexadecimal */
496                       )
497                       + 1       /* turn floor into ceil */
498                       + 2;      /* account for leading sign or alternate form */
499                 else
500                   tmp_length = (unsigned int) (sizeof (unsigned int) * CHAR_BIT * 0.25  /* binary -> hexadecimal */
501                       )
502                       + 1       /* turn floor into ceil */
503                       + 2;      /* account for leading sign or alternate form */
504                 break;
505
506               case 'f':
507               case 'F':
508 # ifdef HAVE_LONG_DOUBLE
509                 if (type == TYPE_LONGDOUBLE)
510                   tmp_length = (unsigned int) (LDBL_MAX_EXP * 0.30103   /* binary -> decimal */
511                       * 2       /* estimate for FLAG_GROUP */
512                       )
513                       + 1       /* turn floor into ceil */
514                       + precision + 10; /* sign, decimal point etc. */
515                 else
516 # endif
517                   tmp_length = (unsigned int) (DBL_MAX_EXP * 0.30103    /* binary -> decimal */
518                       * 2       /* estimate for FLAG_GROUP */
519                       )
520                       + 1       /* turn floor into ceil */
521                       + precision + 10; /* sign, decimal point etc. */
522                 break;
523
524               case 'e':
525               case 'E':
526               case 'g':
527               case 'G':
528               case 'a':
529               case 'A':
530                 tmp_length = precision + 12;    /* sign, decimal point, exponent etc. */
531                 break;
532
533               case 'c':
534 # ifdef HAVE_WINT_T
535                 if (type == TYPE_WIDE_CHAR)
536                   tmp_length = MB_CUR_MAX;
537                 else
538 # endif
539                   tmp_length = 1;
540                 break;
541
542               case 's':
543 # ifdef HAVE_WCHAR_T
544                 if (type == TYPE_WIDE_STRING)
545                   tmp_length = (a.arg[dp->arg_index].a.a_wide_string == NULL ? 6        /* wcslen(L"(null)") */
546                       : local_wcslen (a.arg[dp->arg_index].a.a_wide_string))
547                       * MB_CUR_MAX;
548                 else
549 # endif
550                   tmp_length = a.arg[dp->arg_index].a.a_string == NULL ? 6      /* strlen("(null)") */
551                       : strlen (a.arg[dp->arg_index].a.a_string);
552                 break;
553
554               case 'p':
555                 tmp_length = (unsigned int) (sizeof (void *) * CHAR_BIT * 0.25  /* binary -> hexadecimal */
556                     )
557                     + 1         /* turn floor into ceil */
558                     + 2;        /* account for leading 0x */
559
560                 /* make sure we always have enough space for a plain %p, so + */
561                 if (dp->flags & FLAG_PTR_EXT && a.arg[dp->arg_index].ext_string)
562                   tmp_length += strlen (a.arg[dp->arg_index].ext_string);
563                 break;
564
565               default:
566                 abort ();
567             }
568
569             if (tmp_length < width)
570               tmp_length = width;
571
572             tmp_length++;       /* account for trailing NUL */
573           }
574
575           if (tmp_length <= sizeof (tmpbuf))
576             tmp = tmpbuf;
577           else {
578             tmp = (char *) malloc (tmp_length);
579             if (tmp == NULL) {
580               /* Out of memory.  */
581               if (!(result == resultbuf || result == NULL))
582                 free (result);
583               freea (buf);
584               CLEANUP ();
585               errno = ENOMEM;
586               return NULL;
587             }
588           }
589 #endif
590
591           /* Construct the format string for calling snprintf or
592              sprintf.  */
593           p = buf;
594           *p++ = '%';
595           if (dp->flags & FLAG_GROUP)
596             *p++ = '\'';
597           if (dp->flags & FLAG_LEFT)
598             *p++ = '-';
599           if (dp->flags & FLAG_SHOWSIGN)
600             *p++ = '+';
601           if (dp->flags & FLAG_SPACE)
602             *p++ = ' ';
603           if (dp->flags & FLAG_ALT)
604             *p++ = '#';
605           if (dp->flags & FLAG_ZERO)
606             *p++ = '0';
607           if (dp->width_start != dp->width_end) {
608             size_t n = dp->width_end - dp->width_start;
609             memcpy (p, dp->width_start, n);
610             p += n;
611           }
612           if (dp->precision_start != dp->precision_end) {
613             size_t n = dp->precision_end - dp->precision_start;
614             memcpy (p, dp->precision_start, n);
615             p += n;
616           }
617
618           switch (type) {
619 #ifdef HAVE_INT64_AND_I64
620             case TYPE_INT64:
621             case TYPE_UINT64:
622               *p++ = 'I';
623               *p++ = '6';
624               *p++ = '4';
625               break;
626 #endif
627 #ifdef HAVE_LONG_LONG
628             case TYPE_LONGLONGINT:
629             case TYPE_ULONGLONGINT:
630 #ifdef HAVE_INT64_AND_I64       /* The system (sn)printf uses %I64. Also assume
631                                  * that long long == __int64.
632                                  */
633               *p++ = 'I';
634               *p++ = '6';
635               *p++ = '4';
636               break;
637 #else
638               *p++ = 'l';
639                /*FALLTHROUGH*/
640 #endif
641 #endif
642             case TYPE_LONGINT:
643             case TYPE_ULONGINT:
644 #ifdef HAVE_WINT_T
645             case TYPE_WIDE_CHAR:
646 #endif
647 #ifdef HAVE_WCHAR_T
648             case TYPE_WIDE_STRING:
649 #endif
650               *p++ = 'l';
651               break;
652 #ifdef HAVE_LONG_DOUBLE
653             case TYPE_LONGDOUBLE:
654               *p++ = 'L';
655               break;
656 #endif
657             default:
658               break;
659           }
660           *p = dp->conversion;
661 #if HAVE_SNPRINTF
662           p[1] = '%';
663           p[2] = 'n';
664           p[3] = '\0';
665 #else
666           p[1] = '\0';
667 #endif
668
669           /* Construct the arguments for calling snprintf or sprintf.  */
670           prefix_count = 0;
671           if (dp->width_arg_index >= 0) {
672             if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
673               abort ();
674             prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int;
675           }
676           if (dp->precision_arg_index >= 0) {
677             if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
678               abort ();
679             prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int;
680           }
681 #if HAVE_SNPRINTF
682           /* Prepare checking whether snprintf returns the count
683              via %n.  */
684           ENSURE_ALLOCATION (length + 1);
685           result[length] = '\0';
686 #endif
687
688           for (;;) {
689             size_t maxlen;
690             int count;
691 #if HAVE_SNPRINTF
692             int retcount;
693 #endif
694
695             maxlen = allocated - length;
696             count = -1;
697
698 #if HAVE_SNPRINTF
699             retcount = 0;
700
701 #define SNPRINTF_BUF(arg) \
702                     switch (prefix_count)                                   \
703                       {                                                     \
704                       case 0:                                               \
705                         retcount = snprintf (result + length, maxlen, buf,  \
706                                              arg, &count);                  \
707                         break;                                              \
708                       case 1:                                               \
709                         retcount = snprintf (result + length, maxlen, buf,  \
710                                              prefixes[0], arg, &count);     \
711                         break;                                              \
712                       case 2:                                               \
713                         retcount = snprintf (result + length, maxlen, buf,  \
714                                              prefixes[0], prefixes[1], arg, \
715                                              &count);                       \
716                         break;                                              \
717                       default:                                              \
718                         abort ();                                           \
719                       }
720 #else
721 #define SNPRINTF_BUF(arg) \
722                     switch (prefix_count)                                   \
723                       {                                                     \
724                       case 0:                                               \
725                         count = sprintf (tmp, buf, arg);                    \
726                         break;                                              \
727                       case 1:                                               \
728                         count = sprintf (tmp, buf, prefixes[0], arg);       \
729                         break;                                              \
730                       case 2:                                               \
731                         count = sprintf (tmp, buf, prefixes[0], prefixes[1],\
732                                          arg);                              \
733                         break;                                              \
734                       default:                                              \
735                         abort ();                                           \
736                       }
737 #endif
738
739             switch (type) {
740               case TYPE_SCHAR:
741               {
742                 int arg = a.arg[dp->arg_index].a.a_schar;
743                 SNPRINTF_BUF (arg);
744               }
745                 break;
746               case TYPE_UCHAR:
747               {
748                 unsigned int arg = a.arg[dp->arg_index].a.a_uchar;
749                 SNPRINTF_BUF (arg);
750               }
751                 break;
752               case TYPE_SHORT:
753               {
754                 int arg = a.arg[dp->arg_index].a.a_short;
755                 SNPRINTF_BUF (arg);
756               }
757                 break;
758               case TYPE_USHORT:
759               {
760                 unsigned int arg = a.arg[dp->arg_index].a.a_ushort;
761                 SNPRINTF_BUF (arg);
762               }
763                 break;
764               case TYPE_INT:
765               {
766                 int arg = a.arg[dp->arg_index].a.a_int;
767                 SNPRINTF_BUF (arg);
768               }
769                 break;
770               case TYPE_UINT:
771               {
772                 unsigned int arg = a.arg[dp->arg_index].a.a_uint;
773                 SNPRINTF_BUF (arg);
774               }
775                 break;
776               case TYPE_LONGINT:
777               {
778                 long int arg = a.arg[dp->arg_index].a.a_longint;
779                 SNPRINTF_BUF (arg);
780               }
781                 break;
782               case TYPE_ULONGINT:
783               {
784                 unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint;
785                 SNPRINTF_BUF (arg);
786               }
787                 break;
788 #ifdef HAVE_INT64_AND_I64
789               case TYPE_INT64:
790               {
791                 __int64 arg = a.arg[dp->arg_index].a.a_int64;
792                 SNPRINTF_BUF (arg);
793               }
794                 break;
795               case TYPE_UINT64:
796               {
797                 unsigned __int64 arg = a.arg[dp->arg_index].a.a_uint64;
798                 SNPRINTF_BUF (arg);
799               }
800                 break;
801 #endif
802 #ifdef HAVE_LONG_LONG
803 #ifndef HAVE_LONG_LONG_FORMAT
804               case TYPE_LONGLONGINT:
805               case TYPE_ULONGLONGINT:
806               {
807                 unsigned long long int arg =
808                     a.arg[dp->arg_index].a.a_ulonglongint;
809                 int width;
810                 int precision;
811
812                 width = 0;
813                 if (dp->width_start != dp->width_end) {
814                   if (dp->width_arg_index >= 0) {
815                     int arg;
816
817                     if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
818                       abort ();
819                     arg = a.arg[dp->width_arg_index].a.a_int;
820                     width = (arg < 0 ? -arg : arg);
821                   } else {
822                     const char *digitp = dp->width_start;
823
824                     do
825                       width = width * 10 + (*digitp++ - '0');
826                     while (digitp != dp->width_end);
827                   }
828                 }
829
830                 precision = -1;
831                 if (dp->precision_start != dp->precision_end) {
832                   if (dp->precision_arg_index >= 0) {
833                     int arg;
834
835                     if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
836                       abort ();
837                     arg = a.arg[dp->precision_arg_index].a.a_int;
838                     precision = (arg < 0 ? 0 : arg);
839                   } else {
840                     const char *digitp = dp->precision_start + 1;
841
842                     precision = 0;
843                     do
844                       precision = precision * 10 + (*digitp++ - '0');
845                     while (digitp != dp->precision_end);
846                   }
847                 }
848 #if HAVE_SNPRINTF
849                 count = print_long_long (result + length, maxlen,
850                     width, precision, dp->flags, dp->conversion, arg);
851 #else
852                 count = print_long_long (tmp, tmp_length,
853                     width, precision, dp->flags, dp->conversion, arg);
854 #endif
855               }
856                 break;
857 #else
858               case TYPE_LONGLONGINT:
859               {
860                 long long int arg = a.arg[dp->arg_index].a.a_longlongint;
861                 SNPRINTF_BUF (arg);
862               }
863                 break;
864               case TYPE_ULONGLONGINT:
865               {
866                 unsigned long long int arg =
867                     a.arg[dp->arg_index].a.a_ulonglongint;
868                 SNPRINTF_BUF (arg);
869               }
870                 break;
871 #endif
872 #endif
873               case TYPE_DOUBLE:
874               {
875                 double arg = a.arg[dp->arg_index].a.a_double;
876                 SNPRINTF_BUF (arg);
877               }
878                 break;
879 #ifdef HAVE_LONG_DOUBLE
880               case TYPE_LONGDOUBLE:
881               {
882                 long double arg = a.arg[dp->arg_index].a.a_longdouble;
883                 SNPRINTF_BUF (arg);
884               }
885                 break;
886 #endif
887               case TYPE_CHAR:
888               {
889                 int arg = a.arg[dp->arg_index].a.a_char;
890                 SNPRINTF_BUF (arg);
891               }
892                 break;
893 #ifdef HAVE_WINT_T
894               case TYPE_WIDE_CHAR:
895               {
896                 wint_t arg = a.arg[dp->arg_index].a.a_wide_char;
897                 SNPRINTF_BUF (arg);
898               }
899                 break;
900 #endif
901               case TYPE_STRING:
902               {
903                 const char *arg = a.arg[dp->arg_index].a.a_string == NULL
904                     ? "(null)" : a.arg[dp->arg_index].a.a_string;
905                 SNPRINTF_BUF (arg);
906               }
907                 break;
908 #ifdef HAVE_WCHAR_T
909               case TYPE_WIDE_STRING:
910               {
911                 const wchar_t *arg =
912                     a.arg[dp->arg_index].a.a_wide_string ==
913                     NULL ? L"(null)" : a.arg[dp->arg_index].a.a_wide_string;
914                 SNPRINTF_BUF (arg);
915               }
916                 break;
917 #endif
918               case TYPE_POINTER:
919               {
920                 void *arg = a.arg[dp->arg_index].a.a_pointer;
921                 SNPRINTF_BUF (arg);
922               }
923                 break;
924               case TYPE_POINTER_EXT:
925               {
926                 void *arg = a.arg[dp->arg_index].a.a_pointer;
927
928                 if (a.arg[dp->arg_index].ext_string != NULL) {
929                   arg = a.arg[dp->arg_index].ext_string;
930                   *p = 's';
931                 }
932
933                 SNPRINTF_BUF (arg);
934               }
935                 break;
936               default:
937                 abort ();
938             }
939
940 #if HAVE_SNPRINTF
941             /* Portability: Not all implementations of snprintf()
942                are ISO C 99 compliant.  Determine the number of
943                bytes that snprintf() has produced or would have
944                produced.  */
945             if (count >= 0) {
946               /* Verify that snprintf() has NUL-terminated its
947                  result.  */
948               if (count < maxlen && result[length + count] != '\0')
949                 abort ();
950               /* Portability hack.  */
951               if (retcount > count)
952                 count = retcount;
953             } else {
954               /* snprintf() doesn't understand the '%n'
955                  directive.  */
956               if (p[1] != '\0') {
957                 /* Don't use the '%n' directive; instead, look
958                    at the snprintf() return value.  */
959                 p[1] = '\0';
960                 continue;
961               }
962               count = retcount;
963             }
964 #endif
965
966             /* Attempt to handle failure.  */
967             if (count < 0) {
968               if (!(result == resultbuf || result == NULL))
969                 free (result);
970               freea (buf);
971               CLEANUP ();
972               errno = EINVAL;
973               return NULL;
974             }
975 #if !HAVE_SNPRINTF
976             if (count >= tmp_length)
977               /* tmp_length was incorrectly calculated - fix the
978                  code above!  */
979               abort ();
980 #endif
981
982             /* Make room for the result.  */
983             if (count >= maxlen) {
984               /* Need at least count bytes.  But allocate
985                  proportionally, to avoid looping eternally if
986                  snprintf() reports a too small count.  */
987               size_t n = length + count;
988
989               if (n < 2 * allocated)
990                 n = 2 * allocated;
991
992               ENSURE_ALLOCATION (n);
993 #if HAVE_SNPRINTF
994               continue;
995 #endif
996             }
997 #if HAVE_SNPRINTF
998             /* The snprintf() result did fit.  */
999 #else
1000             /* Append the sprintf() result.  */
1001             memcpy (result + length, tmp, count);
1002             if (tmp != tmpbuf)
1003               free (tmp);
1004 #endif
1005
1006             length += count;
1007             break;
1008           }
1009         }
1010       }
1011     }
1012
1013     /* Add the final NUL.  */
1014     ENSURE_ALLOCATION (length + 1);
1015     result[length] = '\0';
1016
1017     if (result != resultbuf && length + 1 < allocated) {
1018       /* Shrink the allocated memory if possible.  */
1019       char *memory;
1020
1021       memory = (char *) realloc (result, length + 1);
1022       if (memory != NULL)
1023         result = memory;
1024     }
1025
1026     freea (buf);
1027     CLEANUP ();
1028     *lengthp = length;
1029     return result;
1030   }
1031 }