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