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