1 /* vsprintf with automatic memory allocation.
2 Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
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. */
22 # define _GNU_SOURCE 1
31 #include "vasnprintf.h"
33 #include <stdio.h> /* snprintf(), sprintf() */
34 #include <stdlib.h> /* abort(), malloc(), realloc(), free() */
35 #include <string.h> /* memcpy(), strlen() */
36 #include <errno.h> /* errno */
37 #include <limits.h> /* CHAR_BIT */
38 #include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */
39 #include "printf-parse.h"
41 /* For those losing systems which don't have 'alloca' we have to add
42 some additional code emulating it. */
44 # define freea(p) /* nothing */
46 # define alloca(n) malloc (n)
47 # define freea(p) free (p)
52 # define local_wcslen wcslen
54 /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid
55 a dependency towards this library, here is a local substitute. */
57 local_wcslen (const wchar_t *s
)
61 for (ptr
= s
; *ptr
!= (wchar_t) 0; ptr
++)
69 vasnprintf (char *resultbuf
, size_t *lengthp
, const char *format
, va_list args
)
74 if (printf_parse (format
, &d
, &a
) < 0)
85 if (printf_fetchargs (args
, &a
) < 0)
94 (char *) alloca (7 + d
.max_width_length
+ d
.max_precision_length
+ 6);
98 /* Output string accumulator. */
103 if (resultbuf
!= NULL
)
106 allocated
= *lengthp
;
115 result is either == resultbuf or == NULL or malloc-allocated.
116 If length > 0, then result != NULL. */
118 #define ENSURE_ALLOCATION(needed) \
119 if ((needed) > allocated) \
123 allocated = (allocated > 0 ? 2 * allocated : 12); \
124 if ((needed) > allocated) \
125 allocated = (needed); \
126 if (result == resultbuf || result == NULL) \
127 memory = (char *) malloc (allocated); \
129 memory = (char *) realloc (result, allocated); \
131 if (memory == NULL) \
133 if (!(result == resultbuf || result == NULL)) \
140 if (result == resultbuf && length > 0) \
141 memcpy (memory, result, length); \
145 for (cp
= format
, i
= 0, dp
= &d
.dir
[0]; ; cp
= dp
->dir_end
, i
++, dp
++)
147 if (cp
!= dp
->dir_start
)
149 size_t n
= dp
->dir_start
- cp
;
151 ENSURE_ALLOCATION (length
+ n
);
152 memcpy (result
+ length
, cp
, n
);
158 /* Execute a single directive. */
159 if (dp
->conversion
== '%')
161 if (!(dp
->arg_index
< 0))
163 ENSURE_ALLOCATION (length
+ 1);
164 result
[length
] = '%';
169 if (!(dp
->arg_index
>= 0))
172 if (dp
->conversion
== 'n')
174 switch (a
.arg
[dp
->arg_index
].type
)
176 case TYPE_COUNT_SCHAR_POINTER
:
177 *a
.arg
[dp
->arg_index
].a
.a_count_schar_pointer
= length
;
179 case TYPE_COUNT_SHORT_POINTER
:
180 *a
.arg
[dp
->arg_index
].a
.a_count_short_pointer
= length
;
182 case TYPE_COUNT_INT_POINTER
:
183 *a
.arg
[dp
->arg_index
].a
.a_count_int_pointer
= length
;
185 case TYPE_COUNT_LONGINT_POINTER
:
186 *a
.arg
[dp
->arg_index
].a
.a_count_longint_pointer
= length
;
188 #ifdef HAVE_LONG_LONG
189 case TYPE_COUNT_LONGLONGINT_POINTER
:
190 *a
.arg
[dp
->arg_index
].a
.a_count_longlongint_pointer
= length
;
199 arg_type type
= a
.arg
[dp
->arg_index
].type
;
201 unsigned int prefix_count
;
204 unsigned int tmp_length
;
208 /* Allocate a temporary buffer of sufficient size for calling
212 unsigned int precision
;
215 if (dp
->width_start
!= dp
->width_end
)
217 if (dp
->width_arg_index
>= 0)
221 if (!(a
.arg
[dp
->width_arg_index
].type
== TYPE_INT
))
223 arg
= a
.arg
[dp
->width_arg_index
].a
.a_int
;
224 width
= (arg
< 0 ? -arg
: arg
);
228 const char *digitp
= dp
->width_start
;
231 width
= width
* 10 + (*digitp
++ - '0');
232 while (digitp
!= dp
->width_end
);
237 if (dp
->precision_start
!= dp
->precision_end
)
239 if (dp
->precision_arg_index
>= 0)
243 if (!(a
.arg
[dp
->precision_arg_index
].type
== TYPE_INT
))
245 arg
= a
.arg
[dp
->precision_arg_index
].a
.a_int
;
246 precision
= (arg
< 0 ? 0 : arg
);
250 const char *digitp
= dp
->precision_start
+ 1;
254 precision
= precision
* 10 + (*digitp
++ - '0');
255 while (digitp
!= dp
->precision_end
);
259 switch (dp
->conversion
)
262 case 'd': case 'i': case 'u':
263 # ifdef HAVE_LONG_LONG
264 if (type
== TYPE_LONGLONGINT
|| type
== TYPE_ULONGLONGINT
)
266 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
267 * 0.30103 /* binary -> decimal */
268 * 2 /* estimate for FLAG_GROUP */
270 + 1 /* turn floor into ceil */
271 + 1; /* account for leading sign */
274 if (type
== TYPE_LONGINT
|| type
== TYPE_ULONGINT
)
276 (unsigned int) (sizeof (unsigned long) * CHAR_BIT
277 * 0.30103 /* binary -> decimal */
278 * 2 /* estimate for FLAG_GROUP */
280 + 1 /* turn floor into ceil */
281 + 1; /* account for leading sign */
284 (unsigned int) (sizeof (unsigned int) * CHAR_BIT
285 * 0.30103 /* binary -> decimal */
286 * 2 /* estimate for FLAG_GROUP */
288 + 1 /* turn floor into ceil */
289 + 1; /* account for leading sign */
293 # ifdef HAVE_LONG_LONG
294 if (type
== TYPE_LONGLONGINT
|| type
== TYPE_ULONGLONGINT
)
296 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
297 * 0.333334 /* binary -> octal */
299 + 1 /* turn floor into ceil */
300 + 1; /* account for leading sign */
303 if (type
== TYPE_LONGINT
|| type
== TYPE_ULONGINT
)
305 (unsigned int) (sizeof (unsigned long) * CHAR_BIT
306 * 0.333334 /* binary -> octal */
308 + 1 /* turn floor into ceil */
309 + 1; /* account for leading sign */
312 (unsigned int) (sizeof (unsigned int) * CHAR_BIT
313 * 0.333334 /* binary -> octal */
315 + 1 /* turn floor into ceil */
316 + 1; /* account for leading sign */
320 # ifdef HAVE_LONG_LONG
321 if (type
== TYPE_LONGLONGINT
|| type
== TYPE_ULONGLONGINT
)
323 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
324 * 0.25 /* binary -> hexadecimal */
326 + 1 /* turn floor into ceil */
327 + 2; /* account for leading sign or alternate form */
330 if (type
== TYPE_LONGINT
|| type
== TYPE_ULONGINT
)
332 (unsigned int) (sizeof (unsigned long) * CHAR_BIT
333 * 0.25 /* binary -> hexadecimal */
335 + 1 /* turn floor into ceil */
336 + 2; /* account for leading sign or alternate form */
339 (unsigned int) (sizeof (unsigned int) * CHAR_BIT
340 * 0.25 /* binary -> hexadecimal */
342 + 1 /* turn floor into ceil */
343 + 2; /* account for leading sign or alternate form */
347 # ifdef HAVE_LONG_DOUBLE
348 if (type
== TYPE_LONGDOUBLE
)
350 (unsigned int) (LDBL_MAX_EXP
351 * 0.30103 /* binary -> decimal */
352 * 2 /* estimate for FLAG_GROUP */
354 + 1 /* turn floor into ceil */
356 + 10; /* sign, decimal point etc. */
360 (unsigned int) (DBL_MAX_EXP
361 * 0.30103 /* binary -> decimal */
362 * 2 /* estimate for FLAG_GROUP */
364 + 1 /* turn floor into ceil */
366 + 10; /* sign, decimal point etc. */
369 case 'e': case 'E': case 'g': case 'G':
373 + 12; /* sign, decimal point, exponent etc. */
378 if (type
== TYPE_WIDE_CHAR
)
379 tmp_length
= MB_CUR_MAX
;
387 if (type
== TYPE_WIDE_STRING
)
389 local_wcslen (a
.arg
[dp
->arg_index
].a
.a_wide_string
)
393 tmp_length
= strlen (a
.arg
[dp
->arg_index
].a
.a_string
);
398 (unsigned int) (sizeof (void *) * CHAR_BIT
399 * 0.25 /* binary -> hexadecimal */
401 + 1 /* turn floor into ceil */
402 + 2; /* account for leading 0x */
409 if (tmp_length
< width
)
412 tmp_length
++; /* account for trailing NUL */
415 if (tmp_length
<= sizeof (tmpbuf
))
419 tmp
= (char *) malloc (tmp_length
);
423 if (!(result
== resultbuf
|| result
== NULL
))
433 /* Construct the format string for calling snprintf or
437 if (dp
->flags
& FLAG_GROUP
)
439 if (dp
->flags
& FLAG_LEFT
)
441 if (dp
->flags
& FLAG_SHOWSIGN
)
443 if (dp
->flags
& FLAG_SPACE
)
445 if (dp
->flags
& FLAG_ALT
)
447 if (dp
->flags
& FLAG_ZERO
)
449 if (dp
->width_start
!= dp
->width_end
)
451 size_t n
= dp
->width_end
- dp
->width_start
;
452 memcpy (p
, dp
->width_start
, n
);
455 if (dp
->precision_start
!= dp
->precision_end
)
457 size_t n
= dp
->precision_end
- dp
->precision_start
;
458 memcpy (p
, dp
->precision_start
, n
);
464 #ifdef HAVE_LONG_LONG
465 case TYPE_LONGLONGINT
:
466 case TYPE_ULONGLONGINT
:
476 case TYPE_WIDE_STRING
:
480 #ifdef HAVE_LONG_DOUBLE
481 case TYPE_LONGDOUBLE
:
497 /* Construct the arguments for calling snprintf or sprintf. */
499 if (dp
->width_arg_index
>= 0)
501 if (!(a
.arg
[dp
->width_arg_index
].type
== TYPE_INT
))
503 prefixes
[prefix_count
++] = a
.arg
[dp
->width_arg_index
].a
.a_int
;
505 if (dp
->precision_arg_index
>= 0)
507 if (!(a
.arg
[dp
->precision_arg_index
].type
== TYPE_INT
))
509 prefixes
[prefix_count
++] = a
.arg
[dp
->precision_arg_index
].a
.a_int
;
513 /* Prepare checking whether snprintf returns the count
515 ENSURE_ALLOCATION (length
+ 1);
516 result
[length
] = '\0';
525 maxlen
= allocated
- length
;
530 # define SNPRINTF_BUF(arg) \
531 switch (prefix_count) \
534 retcount = snprintf (result + length, maxlen, buf, \
538 retcount = snprintf (result + length, maxlen, buf, \
539 prefixes[0], arg, &count); \
542 retcount = snprintf (result + length, maxlen, buf, \
543 prefixes[0], prefixes[1], arg, \
550 # define SNPRINTF_BUF(arg) \
551 switch (prefix_count) \
554 count = sprintf (tmp, buf, arg); \
557 count = sprintf (tmp, buf, prefixes[0], arg); \
560 count = sprintf (tmp, buf, prefixes[0], prefixes[1],\
572 int arg
= a
.arg
[dp
->arg_index
].a
.a_schar
;
578 unsigned int arg
= a
.arg
[dp
->arg_index
].a
.a_uchar
;
584 int arg
= a
.arg
[dp
->arg_index
].a
.a_short
;
590 unsigned int arg
= a
.arg
[dp
->arg_index
].a
.a_ushort
;
596 int arg
= a
.arg
[dp
->arg_index
].a
.a_int
;
602 unsigned int arg
= a
.arg
[dp
->arg_index
].a
.a_uint
;
608 long int arg
= a
.arg
[dp
->arg_index
].a
.a_longint
;
614 unsigned long int arg
= a
.arg
[dp
->arg_index
].a
.a_ulongint
;
618 #ifdef HAVE_LONG_LONG
619 case TYPE_LONGLONGINT
:
621 long long int arg
= a
.arg
[dp
->arg_index
].a
.a_longlongint
;
625 case TYPE_ULONGLONGINT
:
627 unsigned long long int arg
= a
.arg
[dp
->arg_index
].a
.a_ulonglongint
;
634 double arg
= a
.arg
[dp
->arg_index
].a
.a_double
;
638 #ifdef HAVE_LONG_DOUBLE
639 case TYPE_LONGDOUBLE
:
641 long double arg
= a
.arg
[dp
->arg_index
].a
.a_longdouble
;
648 int arg
= a
.arg
[dp
->arg_index
].a
.a_char
;
655 wint_t arg
= a
.arg
[dp
->arg_index
].a
.a_wide_char
;
662 const char *arg
= a
.arg
[dp
->arg_index
].a
.a_string
;
667 case TYPE_WIDE_STRING
:
669 const wchar_t *arg
= a
.arg
[dp
->arg_index
].a
.a_wide_string
;
676 void *arg
= a
.arg
[dp
->arg_index
].a
.a_pointer
;
685 /* Portability: Not all implementations of snprintf()
686 are ISO C 99 compliant. Determine the number of
687 bytes that snprintf() has produced or would have
691 /* Verify that snprintf() has NUL-terminated its
693 if (count
< maxlen
&& result
[length
+ count
] != '\0')
695 /* Portability hack. */
696 if (retcount
> count
)
701 /* snprintf() doesn't understand the '%n'
705 /* Don't use the '%n' directive; instead, look
706 at the snprintf() return value. */
710 else if (retcount
< 0)
712 /* The system's snprintf is sorely deficient:
713 it doesn't recognize the `%n' directive, and it
714 returns -1 (rather than the length that would
715 have been required) when the buffer is too small.
716 This is the case at with least HPUX 10.20.
717 Double the memory allocation. */
718 size_t n
= allocated
;
719 if (n
< 2 * allocated
)
722 ENSURE_ALLOCATION (n
);
730 /* Attempt to handle failure. */
733 if (!(result
== resultbuf
|| result
== NULL
))
742 if (count
>= tmp_length
)
743 /* tmp_length was incorrectly calculated - fix the
748 /* Make room for the result. */
751 /* Need at least count bytes. But allocate
752 proportionally, to avoid looping eternally if
753 snprintf() reports a too small count. */
754 size_t n
= length
+ count
;
756 if (n
< 2 * allocated
)
759 ENSURE_ALLOCATION (n
);
766 /* The snprintf() result did fit. */
768 /* Append the sprintf() result. */
769 memcpy (result
+ length
, tmp
, count
);
781 /* Add the final NUL. */
782 ENSURE_ALLOCATION (length
+ 1);
783 result
[length
] = '\0';
785 if (result
!= resultbuf
&& length
+ 1 < allocated
)
787 /* Shrink the allocated memory if possible. */
790 memory
= (char *) realloc (result
, length
+ 1);