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