diff options
author | Simon Josefsson <simon@josefsson.org> | 2007-06-11 10:51:03 +0200 |
---|---|---|
committer | Simon Josefsson <simon@josefsson.org> | 2007-06-11 10:51:03 +0200 |
commit | 609e3c695319d84bc009520bba0dbebebed2f289 (patch) | |
tree | 05ab566b815e4340e18cdb27bbf49d72a5f07816 /lgl/vasnprintf.c | |
parent | c86c105e35466f58203a41b2bd9cd94c9967602d (diff) | |
download | gnutls-609e3c695319d84bc009520bba0dbebebed2f289.tar.gz |
Update gnulib files.
Diffstat (limited to 'lgl/vasnprintf.c')
-rw-r--r-- | lgl/vasnprintf.c | 1128 |
1 files changed, 949 insertions, 179 deletions
diff --git a/lgl/vasnprintf.c b/lgl/vasnprintf.c index 54ae10446b..d8ec00ece1 100644 --- a/lgl/vasnprintf.c +++ b/lgl/vasnprintf.c @@ -15,6 +15,35 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/* This file can be parametrized with the following macros: + VASNPRINTF The name of the function being defined. + FCHAR_T The element type of the format string. + DCHAR_T The element type of the destination (result) string. + FCHAR_T_ONLY_ASCII Set to 1 to enable verification that all characters + in the format string are ASCII. MUST be set if + FCHAR_T and DCHAR_T are not the same type. + DIRECTIVE Structure denoting a format directive. + Depends on FCHAR_T. + DIRECTIVES Structure denoting the set of format directives of a + format string. Depends on FCHAR_T. + PRINTF_PARSE Function that parses a format string. + Depends on FCHAR_T. + DCHAR_CPY memcpy like function for DCHAR_T[] arrays. + DCHAR_SET memset like function for DCHAR_T[] arrays. + DCHAR_MBSNLEN mbsnlen like function for DCHAR_T[] arrays. + SNPRINTF The system's snprintf (or similar) function. + This may be either snprintf or swprintf. + TCHAR_T The element type of the argument and result string + of the said SNPRINTF function. This may be either + char or wchar_t. The code exploits that + sizeof (TCHAR_T) | sizeof (DCHAR_T) and + alignof (TCHAR_T) <= alignof (DCHAR_T). + DCHAR_IS_TCHAR Set to 1 if DCHAR_T and TCHAR_T are the same type. + DCHAR_CONV_FROM_ENCODING A function to convert from char[] to DCHAR[]. + DCHAR_IS_UINT8_T Set to 1 if DCHAR_T is uint8_t. + DCHAR_IS_UINT16_T Set to 1 if DCHAR_T is uint16_t. + DCHAR_IS_UINT32_T Set to 1 if DCHAR_T is uint32_t. */ + /* Tell glibc's <stdio.h> to provide a prototype for snprintf(). This must come before <config.h> because <config.h> may include <features.h>, and once <features.h> has been included, it's too late. */ @@ -22,16 +51,20 @@ # define _GNU_SOURCE 1 #endif -#include <config.h> +#ifndef VASNPRINTF +# include <config.h> +#endif #ifndef IN_LIBINTL # include <alloca.h> #endif /* Specification. */ -#if WIDE_CHAR_VERSION -# include "vasnwprintf.h" -#else -# include "vasnprintf.h" +#ifndef VASNPRINTF +# if WIDE_CHAR_VERSION +# include "vasnwprintf.h" +# else +# include "vasnprintf.h" +# endif #endif #include <locale.h> /* localeconv() */ @@ -44,10 +77,12 @@ #if HAVE_NL_LANGINFO # include <langinfo.h> #endif -#if WIDE_CHAR_VERSION -# include "wprintf-parse.h" -#else -# include "printf-parse.h" +#ifndef VASNPRINTF +# if WIDE_CHAR_VERSION +# include "wprintf-parse.h" +# else +# include "printf-parse.h" +# endif #endif /* Checked size_t computations. */ @@ -107,12 +142,32 @@ local_wcslen (const wchar_t *s) # endif #endif +/* Default parameters. */ +#ifndef VASNPRINTF +# if WIDE_CHAR_VERSION +# define VASNPRINTF vasnwprintf +# define FCHAR_T wchar_t +# define DCHAR_T wchar_t +# define TCHAR_T wchar_t +# define DCHAR_IS_TCHAR 1 +# define DIRECTIVE wchar_t_directive +# define DIRECTIVES wchar_t_directives +# define PRINTF_PARSE wprintf_parse +# define DCHAR_CPY wmemcpy +# else +# define VASNPRINTF vasnprintf +# define FCHAR_T char +# define DCHAR_T char +# define TCHAR_T char +# define DCHAR_IS_TCHAR 1 +# define DIRECTIVE char_directive +# define DIRECTIVES char_directives +# define PRINTF_PARSE printf_parse +# define DCHAR_CPY memcpy +# endif +#endif #if WIDE_CHAR_VERSION -# define VASNPRINTF vasnwprintf -# define CHAR_T wchar_t -# define DIRECTIVE wchar_t_directive -# define DIRECTIVES wchar_t_directives -# define PRINTF_PARSE wprintf_parse + /* TCHAR_T is wchar_t. */ # define USE_SNPRINTF 1 # if HAVE_DECL__SNWPRINTF /* On Windows, the function swprintf() has a different signature than @@ -123,11 +178,7 @@ local_wcslen (const wchar_t *s) # define SNPRINTF swprintf # endif #else -# define VASNPRINTF vasnprintf -# define CHAR_T char -# define DIRECTIVE char_directive -# define DIRECTIVES char_directives -# define PRINTF_PARSE printf_parse + /* TCHAR_T is char. */ # /* Use snprintf if it exists under the name 'snprintf' or '_snprintf'. But don't use it on BeOS, since BeOS snprintf produces no output if the size argument is >= 0x3000000. */ @@ -1137,8 +1188,9 @@ floorlog10l (long double x) #endif -CHAR_T * -VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args) +DCHAR_T * +VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, + const FCHAR_T *format, va_list args) { DIRECTIVES d; arguments a; @@ -1154,7 +1206,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar if (a.arg) \ free (a.arg); - if (printf_fetchargs (args, &a) < 0) + if (PRINTF_FETCHARGS (args, &a) < 0) { CLEANUP (); errno = EINVAL; @@ -1163,13 +1215,13 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar { size_t buf_neededlength; - CHAR_T *buf; - CHAR_T *buf_malloced; - const CHAR_T *cp; + TCHAR_T *buf; + TCHAR_T *buf_malloced; + const FCHAR_T *cp; size_t i; DIRECTIVE *dp; /* Output string accumulator. */ - CHAR_T *result; + DCHAR_T *result; size_t allocated; size_t length; @@ -1178,18 +1230,18 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar buf_neededlength = xsum4 (7, d.max_width_length, d.max_precision_length, 6); #if HAVE_ALLOCA - if (buf_neededlength < 4000 / sizeof (CHAR_T)) + if (buf_neededlength < 4000 / sizeof (TCHAR_T)) { - buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T)); + buf = (TCHAR_T *) alloca (buf_neededlength * sizeof (TCHAR_T)); buf_malloced = NULL; } else #endif { - size_t buf_memsize = xtimes (buf_neededlength, sizeof (CHAR_T)); + size_t buf_memsize = xtimes (buf_neededlength, sizeof (TCHAR_T)); if (size_overflow_p (buf_memsize)) goto out_of_memory_1; - buf = (CHAR_T *) malloc (buf_memsize); + buf = (TCHAR_T *) malloc (buf_memsize); if (buf == NULL) goto out_of_memory_1; buf_malloced = buf; @@ -1216,22 +1268,22 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar if ((needed) > allocated) \ { \ size_t memory_size; \ - CHAR_T *memory; \ + DCHAR_T *memory; \ \ allocated = (allocated > 0 ? xtimes (allocated, 2) : 12); \ if ((needed) > allocated) \ allocated = (needed); \ - memory_size = xtimes (allocated, sizeof (CHAR_T)); \ + memory_size = xtimes (allocated, sizeof (DCHAR_T)); \ if (size_overflow_p (memory_size)) \ goto out_of_memory; \ if (result == resultbuf || result == NULL) \ - memory = (CHAR_T *) malloc (memory_size); \ + memory = (DCHAR_T *) malloc (memory_size); \ else \ - memory = (CHAR_T *) realloc (result, memory_size); \ + memory = (DCHAR_T *) realloc (result, memory_size); \ if (memory == NULL) \ goto out_of_memory; \ if (result == resultbuf && length > 0) \ - memcpy (memory, result, length * sizeof (CHAR_T)); \ + DCHAR_CPY (memory, result, length); \ result = memory; \ } @@ -1243,8 +1295,20 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar size_t augmented_length = xsum (length, n); ENSURE_ALLOCATION (augmented_length); - memcpy (result + length, cp, n * sizeof (CHAR_T)); - length = augmented_length; + /* This copies a piece of FCHAR_T[] into a DCHAR_T[]. Here we + need that the format string contains only ASCII characters + if FCHAR_T and DCHAR_T are not the same type. */ + if (sizeof (FCHAR_T) == sizeof (DCHAR_T)) + { + DCHAR_CPY (result + length, (const DCHAR_T *) cp, n); + length = augmented_length; + } + else + { + do + result[length++] = (unsigned char) *cp++; + while (--n > 0); + } } if (i == d.count) break; @@ -1291,6 +1355,470 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar abort (); } } +#if ENABLE_UNISTDIO + /* The unistdio extensions. */ + else if (dp->conversion == 'U') + { + arg_type type = a.arg[dp->arg_index].type; + int flags = dp->flags; + int has_width; + size_t width; + int has_precision; + size_t precision; + + has_width = 0; + width = 0; + if (dp->width_start != dp->width_end) + { + if (dp->width_arg_index != ARG_NONE) + { + int arg; + + if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) + abort (); + arg = a.arg[dp->width_arg_index].a.a_int; + if (arg < 0) + { + /* "A negative field width is taken as a '-' flag + followed by a positive field width." */ + flags |= FLAG_LEFT; + width = (unsigned int) (-arg); + } + else + width = arg; + } + else + { + const FCHAR_T *digitp = dp->width_start; + + do + width = xsum (xtimes (width, 10), *digitp++ - '0'); + while (digitp != dp->width_end); + } + has_width = 1; + } + + has_precision = 0; + precision = 0; + if (dp->precision_start != dp->precision_end) + { + if (dp->precision_arg_index != ARG_NONE) + { + int arg; + + if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) + abort (); + arg = a.arg[dp->precision_arg_index].a.a_int; + /* "A negative precision is taken as if the precision + were omitted." */ + if (arg >= 0) + { + precision = arg; + has_precision = 1; + } + } + else + { + const FCHAR_T *digitp = dp->precision_start + 1; + + precision = 0; + while (digitp != dp->precision_end) + precision = xsum (xtimes (precision, 10), *digitp++ - '0'); + has_precision = 1; + } + } + + switch (type) + { + case TYPE_U8_STRING: + { + const uint8_t *arg = a.arg[dp->arg_index].a.a_u8_string; + const uint8_t *arg_end; + size_t characters; + + if (has_precision) + { + /* Use only PRECISION characters, from the left. */ + arg_end = arg; + characters = 0; + for (; precision > 0; precision--) + { + int count = u8_strmblen (arg_end); + if (count == 0) + break; + if (count < 0) + { + if (!(result == resultbuf || result == NULL)) + free (result); + if (buf_malloced != NULL) + free (buf_malloced); + CLEANUP (); + errno = EILSEQ; + return NULL; + } + arg_end += count; + characters++; + } + } + else if (has_width) + { + /* Use the entire string, and count the number of + characters. */ + arg_end = arg; + characters = 0; + for (;;) + { + int count = u8_strmblen (arg_end); + if (count == 0) + break; + if (count < 0) + { + if (!(result == resultbuf || result == NULL)) + free (result); + if (buf_malloced != NULL) + free (buf_malloced); + CLEANUP (); + errno = EILSEQ; + return NULL; + } + arg_end += count; + characters++; + } + } + else + { + /* Use the entire string. */ + arg_end = arg + u8_strlen (arg); + /* The number of characters doesn't matter. */ + characters = 0; + } + + if (has_width && width > characters + && !(dp->flags & FLAG_LEFT)) + { + size_t n = width - characters; + ENSURE_ALLOCATION (xsum (length, n)); + DCHAR_SET (result + length, ' ', n); + length += n; + } + +# if DCHAR_IS_UINT8_T + { + size_t n = arg_end - arg; + ENSURE_ALLOCATION (xsum (length, n)); + DCHAR_CPY (result + length, arg, n); + length += n; + } +# else + { /* Convert. */ + DCHAR_T *converted = result + length; + size_t converted_len = allocated - length; +# if DCHAR_IS_TCHAR + /* Convert from UTF-8 to locale encoding. */ + if (u8_conv_to_encoding (locale_charset (), + iconveh_question_mark, + arg, arg_end - arg, NULL, + &converted, &converted_len) + < 0) +# else + /* Convert from UTF-8 to UTF-16/UTF-32. */ + converted = + U8_TO_DCHAR (arg, arg_end - arg, + converted, &converted_len); + if (converted == NULL) +# endif + { + int saved_errno = errno; + if (!(result == resultbuf || result == NULL)) + free (result); + if (buf_malloced != NULL) + free (buf_malloced); + CLEANUP (); + errno = saved_errno; + return NULL; + } + if (converted != result + length) + { + ENSURE_ALLOCATION (xsum (length, converted_len)); + DCHAR_CPY (result + length, converted, converted_len); + free (converted); + } + length += converted_len; + } +# endif + + if (has_width && width > characters + && (dp->flags & FLAG_LEFT)) + { + size_t n = width - characters; + ENSURE_ALLOCATION (xsum (length, n)); + DCHAR_SET (result + length, ' ', n); + length += n; + } + } + break; + + case TYPE_U16_STRING: + { + const uint16_t *arg = a.arg[dp->arg_index].a.a_u16_string; + const uint16_t *arg_end; + size_t characters; + + if (has_precision) + { + /* Use only PRECISION characters, from the left. */ + arg_end = arg; + characters = 0; + for (; precision > 0; precision--) + { + int count = u16_strmblen (arg_end); + if (count == 0) + break; + if (count < 0) + { + if (!(result == resultbuf || result == NULL)) + free (result); + if (buf_malloced != NULL) + free (buf_malloced); + CLEANUP (); + errno = EILSEQ; + return NULL; + } + arg_end += count; + characters++; + } + } + else if (has_width) + { + /* Use the entire string, and count the number of + characters. */ + arg_end = arg; + characters = 0; + for (;;) + { + int count = u16_strmblen (arg_end); + if (count == 0) + break; + if (count < 0) + { + if (!(result == resultbuf || result == NULL)) + free (result); + if (buf_malloced != NULL) + free (buf_malloced); + CLEANUP (); + errno = EILSEQ; + return NULL; + } + arg_end += count; + characters++; + } + } + else + { + /* Use the entire string. */ + arg_end = arg + u16_strlen (arg); + /* The number of characters doesn't matter. */ + characters = 0; + } + + if (has_width && width > characters + && !(dp->flags & FLAG_LEFT)) + { + size_t n = width - characters; + ENSURE_ALLOCATION (xsum (length, n)); + DCHAR_SET (result + length, ' ', n); + length += n; + } + +# if DCHAR_IS_UINT16_T + { + size_t n = arg_end - arg; + ENSURE_ALLOCATION (xsum (length, n)); + DCHAR_CPY (result + length, arg, n); + length += n; + } +# else + { /* Convert. */ + DCHAR_T *converted = result + length; + size_t converted_len = allocated - length; +# if DCHAR_IS_TCHAR + /* Convert from UTF-16 to locale encoding. */ + if (u16_conv_to_encoding (locale_charset (), + iconveh_question_mark, + arg, arg_end - arg, NULL, + &converted, &converted_len) + < 0) +# else + /* Convert from UTF-16 to UTF-8/UTF-32. */ + converted = + U16_TO_DCHAR (arg, arg_end - arg, + converted, &converted_len); + if (converted == NULL) +# endif + { + int saved_errno = errno; + if (!(result == resultbuf || result == NULL)) + free (result); + if (buf_malloced != NULL) + free (buf_malloced); + CLEANUP (); + errno = saved_errno; + return NULL; + } + if (converted != result + length) + { + ENSURE_ALLOCATION (xsum (length, converted_len)); + DCHAR_CPY (result + length, converted, converted_len); + free (converted); + } + length += converted_len; + } +# endif + + if (has_width && width > characters + && (dp->flags & FLAG_LEFT)) + { + size_t n = width - characters; + ENSURE_ALLOCATION (xsum (length, n)); + DCHAR_SET (result + length, ' ', n); + length += n; + } + } + break; + + case TYPE_U32_STRING: + { + const uint32_t *arg = a.arg[dp->arg_index].a.a_u32_string; + const uint32_t *arg_end; + size_t characters; + + if (has_precision) + { + /* Use only PRECISION characters, from the left. */ + arg_end = arg; + characters = 0; + for (; precision > 0; precision--) + { + int count = u32_strmblen (arg_end); + if (count == 0) + break; + if (count < 0) + { + if (!(result == resultbuf || result == NULL)) + free (result); + if (buf_malloced != NULL) + free (buf_malloced); + CLEANUP (); + errno = EILSEQ; + return NULL; + } + arg_end += count; + characters++; + } + } + else if (has_width) + { + /* Use the entire string, and count the number of + characters. */ + arg_end = arg; + characters = 0; + for (;;) + { + int count = u32_strmblen (arg_end); + if (count == 0) + break; + if (count < 0) + { + if (!(result == resultbuf || result == NULL)) + free (result); + if (buf_malloced != NULL) + free (buf_malloced); + CLEANUP (); + errno = EILSEQ; + return NULL; + } + arg_end += count; + characters++; + } + } + else + { + /* Use the entire string. */ + arg_end = arg + u32_strlen (arg); + /* The number of characters doesn't matter. */ + characters = 0; + } + + if (has_width && width > characters + && !(dp->flags & FLAG_LEFT)) + { + size_t n = width - characters; + ENSURE_ALLOCATION (xsum (length, n)); + DCHAR_SET (result + length, ' ', n); + length += n; + } + +# if DCHAR_IS_UINT32_T + { + size_t n = arg_end - arg; + ENSURE_ALLOCATION (xsum (length, n)); + DCHAR_CPY (result + length, arg, n); + length += n; + } +# else + { /* Convert. */ + DCHAR_T *converted = result + length; + size_t converted_len = allocated - length; +# if DCHAR_IS_TCHAR + /* Convert from UTF-32 to locale encoding. */ + if (u32_conv_to_encoding (locale_charset (), + iconveh_question_mark, + arg, arg_end - arg, NULL, + &converted, &converted_len) + < 0) +# else + /* Convert from UTF-32 to UTF-8/UTF-16. */ + converted = + U32_TO_DCHAR (arg, arg_end - arg, + converted, &converted_len); + if (converted == NULL) +# endif + { + int saved_errno = errno; + if (!(result == resultbuf || result == NULL)) + free (result); + if (buf_malloced != NULL) + free (buf_malloced); + CLEANUP (); + errno = saved_errno; + return NULL; + } + if (converted != result + length) + { + ENSURE_ALLOCATION (xsum (length, converted_len)); + DCHAR_CPY (result + length, converted, converted_len); + free (converted); + } + length += converted_len; + } +# endif + + if (has_width && width > characters + && (dp->flags & FLAG_LEFT)) + { + size_t n = width - characters; + ENSURE_ALLOCATION (xsum (length, n)); + DCHAR_SET (result + length, ' ', n); + length += n; + } + } + break; + + default: + abort (); + } + } +#endif #if NEED_PRINTF_DIRECTIVE_A && !defined IN_LIBINTL else if (dp->conversion == 'a' || dp->conversion == 'A') { @@ -1301,10 +1829,10 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar int has_precision; size_t precision; size_t tmp_length; - CHAR_T tmpbuf[700]; - CHAR_T *tmp; - CHAR_T *pad_ptr; - CHAR_T *p; + DCHAR_T tmpbuf[700]; + DCHAR_T *tmp; + DCHAR_T *pad_ptr; + DCHAR_T *p; has_width = 0; width = 0; @@ -1329,7 +1857,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } else { - const CHAR_T *digitp = dp->width_start; + const FCHAR_T *digitp = dp->width_start; do width = xsum (xtimes (width, 10), *digitp++ - '0'); @@ -1359,7 +1887,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } else { - const CHAR_T *digitp = dp->precision_start + 1; + const FCHAR_T *digitp = dp->precision_start + 1; precision = 0; while (digitp != dp->precision_end) @@ -1391,16 +1919,16 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */ - if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T)) + if (tmp_length <= sizeof (tmpbuf) / sizeof (DCHAR_T)) tmp = tmpbuf; else { - size_t tmp_memsize = xtimes (tmp_length, sizeof (CHAR_T)); + size_t tmp_memsize = xtimes (tmp_length, sizeof (DCHAR_T)); if (size_overflow_p (tmp_memsize)) /* Overflow, would lead to out of memory. */ goto out_of_memory; - tmp = (CHAR_T *) malloc (tmp_memsize); + tmp = (DCHAR_T *) malloc (tmp_memsize); if (tmp == NULL) /* Out of memory. */ goto out_of_memory; @@ -1535,11 +2063,24 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar { '%', '+', 'd', '\0' }; SNPRINTF (p, 6 + 1, decimal_format, exponent); } -# else - sprintf (p, "%+d", exponent); -# endif while (*p != '\0') p++; +# else + if (sizeof (DCHAR_T) == 1) + { + sprintf ((char *) p, "%+d", exponent); + while (*p != '\0') + p++; + } + else + { + char expbuf[6 + 1]; + const char *ep; + sprintf (expbuf, "%+d", exponent); + for (ep = expbuf; (*p = *ep) != '\0'; ep++) + p++; + } +# endif } END_LONG_DOUBLE_ROUNDING (); @@ -1669,11 +2210,24 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar { '%', '+', 'd', '\0' }; SNPRINTF (p, 6 + 1, decimal_format, exponent); } -# else - sprintf (p, "%+d", exponent); -# endif while (*p != '\0') p++; +# else + if (sizeof (DCHAR_T) == 1) + { + sprintf ((char *) p, "%+d", exponent); + while (*p != '\0') + p++; + } + else + { + char expbuf[6 + 1]; + const char *ep; + sprintf (expbuf, "%+d", exponent); + for (ep = expbuf; (*p = *ep) != '\0'; ep++) + p++; + } +# endif } } } @@ -1682,7 +2236,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar if (has_width && p - tmp < width) { size_t pad = width - (p - tmp); - CHAR_T *end = p + pad; + DCHAR_T *end = p + pad; if (flags & FLAG_LEFT) { @@ -1693,7 +2247,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar else if ((flags & FLAG_ZERO) && pad_ptr != NULL) { /* Pad with zeroes. */ - CHAR_T *q = end; + DCHAR_T *q = end; while (p > pad_ptr) *--q = *--p; @@ -1703,7 +2257,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar else { /* Pad with spaces on the left. */ - CHAR_T *q = end; + DCHAR_T *q = end; while (p > tmp) *--q = *--p; @@ -1731,7 +2285,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } /* Append the result. */ - memcpy (result + length, tmp, count * sizeof (CHAR_T)); + memcpy (result + length, tmp, count * sizeof (DCHAR_T)); if (tmp != tmpbuf) free (tmp); length += count; @@ -1770,10 +2324,10 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar int has_precision; size_t precision; size_t tmp_length; - CHAR_T tmpbuf[700]; - CHAR_T *tmp; - CHAR_T *pad_ptr; - CHAR_T *p; + DCHAR_T tmpbuf[700]; + DCHAR_T *tmp; + DCHAR_T *pad_ptr; + DCHAR_T *p; has_width = 0; width = 0; @@ -1798,7 +2352,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } else { - const CHAR_T *digitp = dp->width_start; + const FCHAR_T *digitp = dp->width_start; do width = xsum (xtimes (width, 10), *digitp++ - '0'); @@ -1828,7 +2382,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } else { - const CHAR_T *digitp = dp->precision_start + 1; + const FCHAR_T *digitp = dp->precision_start + 1; precision = 0; while (digitp != dp->precision_end) @@ -1877,16 +2431,16 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */ - if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T)) + if (tmp_length <= sizeof (tmpbuf) / sizeof (DCHAR_T)) tmp = tmpbuf; else { - size_t tmp_memsize = xtimes (tmp_length, sizeof (CHAR_T)); + size_t tmp_memsize = xtimes (tmp_length, sizeof (DCHAR_T)); if (size_overflow_p (tmp_memsize)) /* Overflow, would lead to out of memory. */ goto out_of_memory; - tmp = (CHAR_T *) malloc (tmp_memsize); + tmp = (DCHAR_T *) malloc (tmp_memsize); if (tmp == NULL) /* Out of memory. */ goto out_of_memory; @@ -2065,11 +2619,24 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar { '%', '+', '.', '2', 'd', '\0' }; SNPRINTF (p, 6 + 1, decimal_format, exponent); } -# else - sprintf (p, "%+.2d", exponent); -# endif while (*p != '\0') p++; +# else + if (sizeof (DCHAR_T) == 1) + { + sprintf ((char *) p, "%+.2d", exponent); + while (*p != '\0') + p++; + } + else + { + char expbuf[6 + 1]; + const char *ep; + sprintf (expbuf, "%+.2d", exponent); + for (ep = expbuf; (*p = *ep) != '\0'; ep++) + p++; + } +# endif } else if (dp->conversion == 'g' || dp->conversion == 'G') { @@ -2209,11 +2776,24 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar { '%', '+', '.', '2', 'd', '\0' }; SNPRINTF (p, 6 + 1, decimal_format, exponent); } -# else - sprintf (p, "%+.2d", exponent); -# endif while (*p != '\0') p++; +# else + if (sizeof (DCHAR_T) == 1) + { + sprintf ((char *) p, "%+.2d", exponent); + while (*p != '\0') + p++; + } + else + { + char expbuf[6 + 1]; + const char *ep; + sprintf (expbuf, "%+.2d", exponent); + for (ep = expbuf; (*p = *ep) != '\0'; ep++) + p++; + } +# endif } free (digits); @@ -2338,7 +2918,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar if (has_width && p - tmp < width) { size_t pad = width - (p - tmp); - CHAR_T *end = p + pad; + DCHAR_T *end = p + pad; if (flags & FLAG_LEFT) { @@ -2349,7 +2929,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar else if ((flags & FLAG_ZERO) && pad_ptr != NULL) { /* Pad with zeroes. */ - CHAR_T *q = end; + DCHAR_T *q = end; while (p > pad_ptr) *--q = *--p; @@ -2359,7 +2939,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar else { /* Pad with spaces on the left. */ - CHAR_T *q = end; + DCHAR_T *q = end; while (p > tmp) *--q = *--p; @@ -2387,7 +2967,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } /* Append the result. */ - memcpy (result + length, tmp, count * sizeof (CHAR_T)); + memcpy (result + length, tmp, count * sizeof (DCHAR_T)); if (tmp != tmpbuf) free (tmp); length += count; @@ -2398,25 +2978,25 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar { arg_type type = a.arg[dp->arg_index].type; int flags = dp->flags; -#if !USE_SNPRINTF || NEED_PRINTF_FLAG_ZERO +#if !USE_SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO int has_width; size_t width; #endif -#if NEED_PRINTF_FLAG_ZERO +#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO int pad_ourselves; #else # define pad_ourselves 0 #endif - CHAR_T *fbp; + TCHAR_T *fbp; unsigned int prefix_count; int prefixes[2]; #if !USE_SNPRINTF size_t tmp_length; - CHAR_T tmpbuf[700]; - CHAR_T *tmp; + TCHAR_T tmpbuf[700]; + TCHAR_T *tmp; #endif -#if !USE_SNPRINTF || NEED_PRINTF_FLAG_ZERO +#if !USE_SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO has_width = 0; width = 0; if (dp->width_start != dp->width_end) @@ -2440,7 +3020,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } else { - const CHAR_T *digitp = dp->width_start; + const FCHAR_T *digitp = dp->width_start; do width = xsum (xtimes (width, 10), *digitp++ - '0'); @@ -2470,7 +3050,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } else { - const CHAR_T *digitp = dp->precision_start + 1; + const FCHAR_T *digitp = dp->precision_start + 1; precision = 0; while (digitp != dp->precision_end) @@ -2650,22 +3230,32 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar abort (); } +# if ENABLE_UNISTDIO + /* Padding considers the number of characters, therefore the + number of elements after padding may be + > max (tmp_length, width) + but is certainly + <= tmp_length + width. */ + tmp_length = xsum (tmp_length, width); +# else + /* Padding considers the number of elements, says POSIX. */ if (tmp_length < width) tmp_length = width; +# endif tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */ } - if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T)) + if (tmp_length <= sizeof (tmpbuf) / sizeof (TCHAR_T)) tmp = tmpbuf; else { - size_t tmp_memsize = xtimes (tmp_length, sizeof (CHAR_T)); + size_t tmp_memsize = xtimes (tmp_length, sizeof (TCHAR_T)); if (size_overflow_p (tmp_memsize)) /* Overflow, would lead to out of memory. */ goto out_of_memory; - tmp = (CHAR_T *) malloc (tmp_memsize); + tmp = (TCHAR_T *) malloc (tmp_memsize); if (tmp == NULL) /* Out of memory. */ goto out_of_memory; @@ -2673,11 +3263,20 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar #endif /* Decide whether to perform the padding ourselves. */ -#if NEED_PRINTF_FLAG_ZERO +#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO switch (dp->conversion) { +# if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO + /* If we need conversion from TCHAR_T[] to DCHAR_T[], we need + to perform the padding after this conversion. Functions + with unistdio extensions perform the padding based on + character count rather than element count. */ + case 'c': case 's': +# endif +# if NEED_PRINTF_FLAG_ZERO case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': case 'a': case 'A': +# endif pad_ourselves = 1; break; default: @@ -2713,15 +3312,39 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar if (dp->width_start != dp->width_end) { size_t n = dp->width_end - dp->width_start; - memcpy (fbp, dp->width_start, n * sizeof (CHAR_T)); - fbp += n; + /* The width specification is known to consist only + of standard ASCII characters. */ + if (sizeof (FCHAR_T) == sizeof (TCHAR_T)) + { + memcpy (fbp, dp->width_start, n * sizeof (TCHAR_T)); + fbp += n; + } + else + { + const FCHAR_T *mp = dp->width_start; + do + *fbp++ = (unsigned char) *mp++; + while (--n > 0); + } } } if (dp->precision_start != dp->precision_end) { size_t n = dp->precision_end - dp->precision_start; - memcpy (fbp, dp->precision_start, n * sizeof (CHAR_T)); - fbp += n; + /* The precision specification is known to consist only + of standard ASCII characters. */ + if (sizeof (FCHAR_T) == sizeof (TCHAR_T)) + { + memcpy (fbp, dp->precision_start, n * sizeof (TCHAR_T)); + fbp += n; + } + else + { + const FCHAR_T *mp = dp->precision_start; + do + *fbp++ = (unsigned char) *mp++; + while (--n > 0); + } } switch (type) @@ -2785,39 +3408,46 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } #if USE_SNPRINTF + /* The SNPRINTF result is appended after result[0..length]. + The latter is an array of DCHAR_T; SNPRINTF appends an + array of TCHAR_T to it. This is possible because + sizeof (TCHAR_T) divides sizeof (DCHAR_T) and + alignof (TCHAR_T) <= alignof (DCHAR_T). */ +# define TCHARS_PER_DCHAR (sizeof (DCHAR_T) / sizeof (TCHAR_T)) /* Prepare checking whether snprintf returns the count via %n. */ ENSURE_ALLOCATION (xsum (length, 1)); - result[length] = '\0'; + *(TCHAR_T *) (result + length) = '\0'; #endif for (;;) { - size_t maxlen; - int count; - int retcount; - - maxlen = allocated - length; - count = -1; - retcount = 0; + int count = -1; #if USE_SNPRINTF - /* SNPRINTF can fail if maxlen > INT_MAX. */ - if (maxlen > INT_MAX) + int retcount = 0; + size_t maxlen = allocated - length; + /* SNPRINTF can fail if its second argument is + > INT_MAX. */ + if (maxlen > INT_MAX / TCHARS_PER_DCHAR) goto overflow; + maxlen = maxlen * TCHARS_PER_DCHAR; # define SNPRINTF_BUF(arg) \ switch (prefix_count) \ { \ case 0: \ - retcount = SNPRINTF (result + length, maxlen, buf, \ + retcount = SNPRINTF ((TCHAR_T *) (result + length), \ + maxlen, buf, \ arg, &count); \ break; \ case 1: \ - retcount = SNPRINTF (result + length, maxlen, buf, \ + retcount = SNPRINTF ((TCHAR_T *) (result + length), \ + maxlen, buf, \ prefixes[0], arg, &count); \ break; \ case 2: \ - retcount = SNPRINTF (result + length, maxlen, buf, \ + retcount = SNPRINTF ((TCHAR_T *) (result + length), \ + maxlen, buf, \ prefixes[0], prefixes[1], arg, \ &count); \ break; \ @@ -2966,7 +3596,8 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar { /* Verify that snprintf() has NUL-terminated its result. */ - if (count < maxlen && result[length + count] != '\0') + if (count < maxlen + && ((TCHAR_T *) (result + length)) [count] != '\0') abort (); /* Portability hack. */ if (retcount > count) @@ -3016,109 +3647,245 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar return NULL; } - /* Make room for the result. */ +#if USE_SNPRINTF + /* Handle overflow of the allocated buffer. */ if (count >= maxlen) { - /* Need at least count bytes. But allocate - proportionally, to avoid looping eternally if - snprintf() reports a too small count. */ + /* Need at least count * sizeof (TCHAR_T) bytes. But + allocate proportionally, to avoid looping eternally + if snprintf() reports a too small count. */ size_t n = - xmax (xsum (length, count), xtimes (allocated, 2)); + xmax (xsum (length, + (count + TCHARS_PER_DCHAR - 1) + / TCHARS_PER_DCHAR), + xtimes (allocated, 2)); ENSURE_ALLOCATION (n); -#if USE_SNPRINTF continue; -#else - maxlen = allocated - length; -#endif } +#endif - /* Perform padding. */ -#if NEED_PRINTF_FLAG_ZERO - if (pad_ourselves && has_width && count < width) +#if !DCHAR_IS_TCHAR +# if !USE_SNPRINTF + if (count >= tmp_length) + /* tmp_length was incorrectly calculated - fix the + code above! */ + abort (); +# endif + + /* Convert from TCHAR_T[] to DCHAR_T[]. */ + if (dp->conversion == 'c' || dp->conversion == 's') { + /* type = TYPE_CHAR or TYPE_WIDE_CHAR or TYPE_STRING + TYPE_WIDE_STRING. + The result string is not certainly ASCII. */ + const TCHAR_T *tmpsrc; + DCHAR_T *tmpdst; + size_t tmpdst_len; + /* This code assumes that TCHAR_T is 'char'. */ + typedef int TCHAR_T_verify + [2 * (sizeof (TCHAR_T) == 1) - 1]; # if USE_SNPRINTF - /* Make room for the result. */ - if (width >= maxlen) + tmpsrc = (TCHAR_T *) (result + length); +# else + tmpsrc = tmp; +# endif + tmpdst = NULL; + tmpdst_len = 0; + if (DCHAR_CONV_FROM_ENCODING (locale_charset (), + iconveh_question_mark, + tmpsrc, count, + NULL, + &tmpdst, &tmpdst_len) + < 0) { - /* Need at least width bytes. But allocate - proportionally, to avoid looping eternally if - snprintf() reports a too small count. */ - size_t n = - xmax (xsum (length + 1, width), - xtimes (allocated, 2)); - - length += count; - ENSURE_ALLOCATION (n); - length -= count; - maxlen = allocated - length; /* > width */ + int saved_errno = errno; + if (!(result == resultbuf || result == NULL)) + free (result); + if (buf_malloced != NULL) + free (buf_malloced); + CLEANUP (); + errno = saved_errno; + return NULL; } - /* Here width < maxlen. */ + ENSURE_ALLOCATION (xsum (length, tmpdst_len)); + DCHAR_CPY (result + length, tmpdst, tmpdst_len); + free (tmpdst); + count = tmpdst_len; + } + else + { + /* The result string is ASCII. + Simple 1:1 conversion. */ +# if USE_SNPRINTF + /* If sizeof (DCHAR_T) == sizeof (TCHAR_T), it's a + no-op conversion, in-place on the array starting + at (result + length). */ + if (sizeof (DCHAR_T) != sizeof (TCHAR_T)) # endif - { + { + const TCHAR_T *tmpsrc; + DCHAR_T *tmpdst; + size_t n; + # if USE_SNPRINTF - CHAR_T * const rp = result + length; + if (result == resultbuf) + { + tmpsrc = (TCHAR_T *) (result + length); + /* ENSURE_ALLOCATION will not move tmpsrc + (because it's part of resultbuf). */ + ENSURE_ALLOCATION (xsum (length, count)); + } + else + { + /* ENSURE_ALLOCATION will move the array + (because it uses realloc(). */ + ENSURE_ALLOCATION (xsum (length, count)); + tmpsrc = (TCHAR_T *) (result + length); + } # else - CHAR_T * const rp = tmp; + tmpsrc = tmp; + ENSURE_ALLOCATION (xsum (length, count)); # endif - CHAR_T *p = rp + count; - size_t pad = width - count; - CHAR_T *end = p + pad; - CHAR_T *pad_ptr = (*rp == '-' ? rp + 1 : rp); - /* No zero-padding of "inf" and "nan". */ - if ((*pad_ptr >= 'A' && *pad_ptr <= 'Z') - || (*pad_ptr >= 'a' && *pad_ptr <= 'z')) - pad_ptr = NULL; - /* The generated string now extends from rp to p, - with the zero padding insertion point being at - pad_ptr. */ - - if (flags & FLAG_LEFT) - { - /* Pad with spaces on the right. */ - for (; pad > 0; pad--) - *p++ = ' '; - } - else if ((flags & FLAG_ZERO) && pad_ptr != NULL) - { - /* Pad with zeroes. */ - CHAR_T *q = end; + tmpdst = result + length; + /* Copy backwards, because of overlapping. */ + tmpsrc += count; + tmpdst += count; + for (n = count; n > 0; n--) + *--tmpdst = (unsigned char) *--tmpsrc; + } + } +#endif - while (p > pad_ptr) - *--q = *--p; - for (; pad > 0; pad--) - *p++ = '0'; - } - else +#if DCHAR_IS_TCHAR && !USE_SNPRINTF + /* Make room for the result. */ + if (count > allocated - length) + { + /* Need at least count elements. But allocate + proportionally. */ + size_t n = + xmax (xsum (length, count), xtimes (allocated, 2)); + + ENSURE_ALLOCATION (n); + } +#endif + + /* Here count <= allocated - length. */ + + /* Perform padding. */ +#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO + if (pad_ourselves && has_width) + { + size_t w; +# if ENABLE_UNISTDIO + /* Outside POSIX, it's preferrable to compare the width + against the number of _characters_ of the converted + value. */ + w = DCHAR_MBSNLEN (result + length, count); +# else + /* The width is compared against the number of _bytes_ + of the converted value, says POSIX. */ + w = count; +# endif + if (w < width) + { + size_t pad = width - w; +# if USE_SNPRINTF + /* Make room for the result. */ + if (xsum (count, pad) > allocated - length) + { + /* Need at least count + pad elements. But + allocate proportionally. */ + size_t n = + xmax (xsum3 (length, count, pad), + xtimes (allocated, 2)); + + length += count; + ENSURE_ALLOCATION (n); + length -= count; + } + /* Here count + pad <= allocated - length. */ +# endif { - /* Pad with spaces on the left. */ - CHAR_T *q = end; +# if !DCHAR_IS_TCHAR || USE_SNPRINTF + DCHAR_T * const rp = result + length; +# else + DCHAR_T * const rp = tmp; +# endif + DCHAR_T *p = rp + count; + DCHAR_T *end = p + pad; +# if NEED_PRINTF_FLAG_ZERO + DCHAR_T *pad_ptr; +# if !DCHAR_IS_TCHAR + if (dp->conversion == 'c' + || dp->conversion == 's') + /* No zero-padding for string directives. */ + pad_ptr = NULL; + else +# endif + { + pad_ptr = (*rp == '-' ? rp + 1 : rp); + /* No zero-padding of "inf" and "nan". */ + if ((*pad_ptr >= 'A' && *pad_ptr <= 'Z') + || (*pad_ptr >= 'a' && *pad_ptr <= 'z')) + pad_ptr = NULL; + } +# endif + /* The generated string now extends from rp to p, + with the zero padding insertion point being at + pad_ptr. */ - while (p > rp) - *--q = *--p; - for (; pad > 0; pad--) - *p++ = ' '; - } + count = count + pad; /* = end - rp */ - count = width; /* = count + pad = end - rp */ - } + if (flags & FLAG_LEFT) + { + /* Pad with spaces on the right. */ + for (; pad > 0; pad--) + *p++ = ' '; + } +# if NEED_PRINTF_FLAG_ZERO + else if ((flags & FLAG_ZERO) && pad_ptr != NULL) + { + /* Pad with zeroes. */ + DCHAR_T *q = end; + + while (p > pad_ptr) + *--q = *--p; + for (; pad > 0; pad--) + *p++ = '0'; + } +# endif + else + { + /* Pad with spaces on the left. */ + DCHAR_T *q = end; + + while (p > rp) + *--q = *--p; + for (; pad > 0; pad--) + *p++ = ' '; + } + } + } } #endif -#if !USE_SNPRINTF +#if DCHAR_IS_TCHAR && !USE_SNPRINTF if (count >= tmp_length) /* tmp_length was incorrectly calculated - fix the code above! */ abort (); #endif - /* Here still count < maxlen. */ + /* Here still count <= allocated - length. */ -#if USE_SNPRINTF +#if !DCHAR_IS_TCHAR || USE_SNPRINTF /* The snprintf() result did fit. */ #else /* Append the sprintf() result. */ - memcpy (result + length, tmp, count * sizeof (CHAR_T)); + memcpy (result + length, tmp, count * sizeof (DCHAR_T)); +#endif +#if !USE_SNPRINTF if (tmp != tmpbuf) free (tmp); #endif @@ -3127,7 +3894,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar if (dp->conversion == 'F') { /* Convert the %f result to upper case for %F. */ - CHAR_T *rp = result + length; + DCHAR_T *rp = result + length; size_t rc; for (rc = count; rc > 0; rc--, rp++) if (*rp >= 'a' && *rp <= 'z') @@ -3149,9 +3916,9 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar if (result != resultbuf && length + 1 < allocated) { /* Shrink the allocated memory if possible. */ - CHAR_T *memory; + DCHAR_T *memory; - memory = (CHAR_T *) realloc (result, (length + 1) * sizeof (CHAR_T)); + memory = (DCHAR_T *) realloc (result, (length + 1) * sizeof (DCHAR_T)); if (memory != NULL) result = memory; } @@ -3187,10 +3954,13 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } } +#undef TCHARS_PER_DCHAR #undef SNPRINTF #undef USE_SNPRINTF #undef PRINTF_PARSE #undef DIRECTIVES #undef DIRECTIVE -#undef CHAR_T +#undef TCHAR_T +#undef DCHAR_T +#undef FCHAR_T #undef VASNPRINTF |