diff options
Diffstat (limited to 'gl/vasnprintf.c')
| -rw-r--r-- | gl/vasnprintf.c | 714 |
1 files changed, 657 insertions, 57 deletions
diff --git a/gl/vasnprintf.c b/gl/vasnprintf.c index 93aef6f2..7ac9f436 100644 --- a/gl/vasnprintf.c +++ b/gl/vasnprintf.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* vsprintf with automatic memory allocation. | 1 | /* vsprintf with automatic memory allocation. |
| 2 | Copyright (C) 1999, 2002-2008 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2002-2009 Free Software Foundation, Inc. |
| 3 | 3 | ||
| 4 | This program is free software; you can redistribute it and/or modify | 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 | 5 | it under the terms of the GNU General Public License as published by |
| @@ -117,29 +117,6 @@ | |||
| 117 | # include "fpucw.h" | 117 | # include "fpucw.h" |
| 118 | #endif | 118 | #endif |
| 119 | 119 | ||
| 120 | #if HAVE_WCHAR_T | ||
| 121 | # if HAVE_WCSLEN | ||
| 122 | # define local_wcslen wcslen | ||
| 123 | # else | ||
| 124 | /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid | ||
| 125 | a dependency towards this library, here is a local substitute. | ||
| 126 | Define this substitute only once, even if this file is included | ||
| 127 | twice in the same compilation unit. */ | ||
| 128 | # ifndef local_wcslen_defined | ||
| 129 | # define local_wcslen_defined 1 | ||
| 130 | static size_t | ||
| 131 | local_wcslen (const wchar_t *s) | ||
| 132 | { | ||
| 133 | const wchar_t *ptr; | ||
| 134 | |||
| 135 | for (ptr = s; *ptr != (wchar_t) 0; ptr++) | ||
| 136 | ; | ||
| 137 | return ptr - s; | ||
| 138 | } | ||
| 139 | # endif | ||
| 140 | # endif | ||
| 141 | #endif | ||
| 142 | |||
| 143 | /* Default parameters. */ | 120 | /* Default parameters. */ |
| 144 | #ifndef VASNPRINTF | 121 | #ifndef VASNPRINTF |
| 145 | # if WIDE_CHAR_VERSION | 122 | # if WIDE_CHAR_VERSION |
| @@ -152,6 +129,7 @@ local_wcslen (const wchar_t *s) | |||
| 152 | # define DIRECTIVES wchar_t_directives | 129 | # define DIRECTIVES wchar_t_directives |
| 153 | # define PRINTF_PARSE wprintf_parse | 130 | # define PRINTF_PARSE wprintf_parse |
| 154 | # define DCHAR_CPY wmemcpy | 131 | # define DCHAR_CPY wmemcpy |
| 132 | # define DCHAR_SET wmemset | ||
| 155 | # else | 133 | # else |
| 156 | # define VASNPRINTF vasnprintf | 134 | # define VASNPRINTF vasnprintf |
| 157 | # define FCHAR_T char | 135 | # define FCHAR_T char |
| @@ -162,6 +140,7 @@ local_wcslen (const wchar_t *s) | |||
| 162 | # define DIRECTIVES char_directives | 140 | # define DIRECTIVES char_directives |
| 163 | # define PRINTF_PARSE printf_parse | 141 | # define PRINTF_PARSE printf_parse |
| 164 | # define DCHAR_CPY memcpy | 142 | # define DCHAR_CPY memcpy |
| 143 | # define DCHAR_SET memset | ||
| 165 | # endif | 144 | # endif |
| 166 | #endif | 145 | #endif |
| 167 | #if WIDE_CHAR_VERSION | 146 | #if WIDE_CHAR_VERSION |
| @@ -215,6 +194,64 @@ local_wcslen (const wchar_t *s) | |||
| 215 | #undef remainder | 194 | #undef remainder |
| 216 | #define remainder rem | 195 | #define remainder rem |
| 217 | 196 | ||
| 197 | #if !USE_SNPRINTF && !WIDE_CHAR_VERSION | ||
| 198 | # if (HAVE_STRNLEN && !defined _AIX) | ||
| 199 | # define local_strnlen strnlen | ||
| 200 | # else | ||
| 201 | # ifndef local_strnlen_defined | ||
| 202 | # define local_strnlen_defined 1 | ||
| 203 | static size_t | ||
| 204 | local_strnlen (const char *string, size_t maxlen) | ||
| 205 | { | ||
| 206 | const char *end = memchr (string, '\0', maxlen); | ||
| 207 | return end ? (size_t) (end - string) : maxlen; | ||
| 208 | } | ||
| 209 | # endif | ||
| 210 | # endif | ||
| 211 | #endif | ||
| 212 | |||
| 213 | #if (!USE_SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && HAVE_WCHAR_T && (WIDE_CHAR_VERSION || DCHAR_IS_TCHAR) | ||
| 214 | # if HAVE_WCSLEN | ||
| 215 | # define local_wcslen wcslen | ||
| 216 | # else | ||
| 217 | /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid | ||
| 218 | a dependency towards this library, here is a local substitute. | ||
| 219 | Define this substitute only once, even if this file is included | ||
| 220 | twice in the same compilation unit. */ | ||
| 221 | # ifndef local_wcslen_defined | ||
| 222 | # define local_wcslen_defined 1 | ||
| 223 | static size_t | ||
| 224 | local_wcslen (const wchar_t *s) | ||
| 225 | { | ||
| 226 | const wchar_t *ptr; | ||
| 227 | |||
| 228 | for (ptr = s; *ptr != (wchar_t) 0; ptr++) | ||
| 229 | ; | ||
| 230 | return ptr - s; | ||
| 231 | } | ||
| 232 | # endif | ||
| 233 | # endif | ||
| 234 | #endif | ||
| 235 | |||
| 236 | #if !USE_SNPRINTF && HAVE_WCHAR_T && WIDE_CHAR_VERSION | ||
| 237 | # if HAVE_WCSNLEN | ||
| 238 | # define local_wcsnlen wcsnlen | ||
| 239 | # else | ||
| 240 | # ifndef local_wcsnlen_defined | ||
| 241 | # define local_wcsnlen_defined 1 | ||
| 242 | static size_t | ||
| 243 | local_wcsnlen (const wchar_t *s, size_t maxlen) | ||
| 244 | { | ||
| 245 | const wchar_t *ptr; | ||
| 246 | |||
| 247 | for (ptr = s; maxlen > 0 && *ptr != (wchar_t) 0; ptr++, maxlen--) | ||
| 248 | ; | ||
| 249 | return ptr - s; | ||
| 250 | } | ||
| 251 | # endif | ||
| 252 | # endif | ||
| 253 | #endif | ||
| 254 | |||
| 218 | #if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && !defined IN_LIBINTL | 255 | #if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && !defined IN_LIBINTL |
| 219 | /* Determine the decimal-point character according to the current locale. */ | 256 | /* Determine the decimal-point character according to the current locale. */ |
| 220 | # ifndef decimal_point_char_defined | 257 | # ifndef decimal_point_char_defined |
| @@ -376,7 +413,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q) | |||
| 376 | Normalise [q[m-1],...,q[0]], yields q. | 413 | Normalise [q[m-1],...,q[0]], yields q. |
| 377 | If m>=n>1, perform a multiple-precision division: | 414 | If m>=n>1, perform a multiple-precision division: |
| 378 | We have a/b < beta^(m-n+1). | 415 | We have a/b < beta^(m-n+1). |
| 379 | s:=intDsize-1-(hightest bit in b[n-1]), 0<=s<intDsize. | 416 | s:=intDsize-1-(highest bit in b[n-1]), 0<=s<intDsize. |
| 380 | Shift a and b left by s bits, copying them. r:=a. | 417 | Shift a and b left by s bits, copying them. r:=a. |
| 381 | r=[r[m],...,r[0]], b=[b[n-1],...,b[0]] with b[n-1]>=beta/2. | 418 | r=[r[m],...,r[0]], b=[b[n-1],...,b[0]] with b[n-1]>=beta/2. |
| 382 | For j=m-n,...,0: {Here 0 <= r < b*beta^(j+1).} | 419 | For j=m-n,...,0: {Here 0 <= r < b*beta^(j+1).} |
| @@ -1762,18 +1799,18 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 1762 | size_t converted_len = allocated - length; | 1799 | size_t converted_len = allocated - length; |
| 1763 | # if DCHAR_IS_TCHAR | 1800 | # if DCHAR_IS_TCHAR |
| 1764 | /* Convert from UTF-8 to locale encoding. */ | 1801 | /* Convert from UTF-8 to locale encoding. */ |
| 1765 | if (u8_conv_to_encoding (locale_charset (), | 1802 | converted = |
| 1766 | iconveh_question_mark, | 1803 | u8_conv_to_encoding (locale_charset (), |
| 1767 | arg, arg_end - arg, NULL, | 1804 | iconveh_question_mark, |
| 1768 | &converted, &converted_len) | 1805 | arg, arg_end - arg, NULL, |
| 1769 | < 0) | 1806 | converted, &converted_len); |
| 1770 | # else | 1807 | # else |
| 1771 | /* Convert from UTF-8 to UTF-16/UTF-32. */ | 1808 | /* Convert from UTF-8 to UTF-16/UTF-32. */ |
| 1772 | converted = | 1809 | converted = |
| 1773 | U8_TO_DCHAR (arg, arg_end - arg, | 1810 | U8_TO_DCHAR (arg, arg_end - arg, |
| 1774 | converted, &converted_len); | 1811 | converted, &converted_len); |
| 1775 | if (converted == NULL) | ||
| 1776 | # endif | 1812 | # endif |
| 1813 | if (converted == NULL) | ||
| 1777 | { | 1814 | { |
| 1778 | int saved_errno = errno; | 1815 | int saved_errno = errno; |
| 1779 | if (!(result == resultbuf || result == NULL)) | 1816 | if (!(result == resultbuf || result == NULL)) |
| @@ -1890,18 +1927,18 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 1890 | size_t converted_len = allocated - length; | 1927 | size_t converted_len = allocated - length; |
| 1891 | # if DCHAR_IS_TCHAR | 1928 | # if DCHAR_IS_TCHAR |
| 1892 | /* Convert from UTF-16 to locale encoding. */ | 1929 | /* Convert from UTF-16 to locale encoding. */ |
| 1893 | if (u16_conv_to_encoding (locale_charset (), | 1930 | converted = |
| 1894 | iconveh_question_mark, | 1931 | u16_conv_to_encoding (locale_charset (), |
| 1895 | arg, arg_end - arg, NULL, | 1932 | iconveh_question_mark, |
| 1896 | &converted, &converted_len) | 1933 | arg, arg_end - arg, NULL, |
| 1897 | < 0) | 1934 | converted, &converted_len); |
| 1898 | # else | 1935 | # else |
| 1899 | /* Convert from UTF-16 to UTF-8/UTF-32. */ | 1936 | /* Convert from UTF-16 to UTF-8/UTF-32. */ |
| 1900 | converted = | 1937 | converted = |
| 1901 | U16_TO_DCHAR (arg, arg_end - arg, | 1938 | U16_TO_DCHAR (arg, arg_end - arg, |
| 1902 | converted, &converted_len); | 1939 | converted, &converted_len); |
| 1903 | if (converted == NULL) | ||
| 1904 | # endif | 1940 | # endif |
| 1941 | if (converted == NULL) | ||
| 1905 | { | 1942 | { |
| 1906 | int saved_errno = errno; | 1943 | int saved_errno = errno; |
| 1907 | if (!(result == resultbuf || result == NULL)) | 1944 | if (!(result == resultbuf || result == NULL)) |
| @@ -2018,18 +2055,18 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 2018 | size_t converted_len = allocated - length; | 2055 | size_t converted_len = allocated - length; |
| 2019 | # if DCHAR_IS_TCHAR | 2056 | # if DCHAR_IS_TCHAR |
| 2020 | /* Convert from UTF-32 to locale encoding. */ | 2057 | /* Convert from UTF-32 to locale encoding. */ |
| 2021 | if (u32_conv_to_encoding (locale_charset (), | 2058 | converted = |
| 2022 | iconveh_question_mark, | 2059 | u32_conv_to_encoding (locale_charset (), |
| 2023 | arg, arg_end - arg, NULL, | 2060 | iconveh_question_mark, |
| 2024 | &converted, &converted_len) | 2061 | arg, arg_end - arg, NULL, |
| 2025 | < 0) | 2062 | converted, &converted_len); |
| 2026 | # else | 2063 | # else |
| 2027 | /* Convert from UTF-32 to UTF-8/UTF-16. */ | 2064 | /* Convert from UTF-32 to UTF-8/UTF-16. */ |
| 2028 | converted = | 2065 | converted = |
| 2029 | U32_TO_DCHAR (arg, arg_end - arg, | 2066 | U32_TO_DCHAR (arg, arg_end - arg, |
| 2030 | converted, &converted_len); | 2067 | converted, &converted_len); |
| 2031 | if (converted == NULL) | ||
| 2032 | # endif | 2068 | # endif |
| 2069 | if (converted == NULL) | ||
| 2033 | { | 2070 | { |
| 2034 | int saved_errno = errno; | 2071 | int saved_errno = errno; |
| 2035 | if (!(result == resultbuf || result == NULL)) | 2072 | if (!(result == resultbuf || result == NULL)) |
| @@ -2066,6 +2103,522 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 2066 | } | 2103 | } |
| 2067 | } | 2104 | } |
| 2068 | #endif | 2105 | #endif |
| 2106 | #if (!USE_SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && HAVE_WCHAR_T | ||
| 2107 | else if (dp->conversion == 's' | ||
| 2108 | # if WIDE_CHAR_VERSION | ||
| 2109 | && a.arg[dp->arg_index].type != TYPE_WIDE_STRING | ||
| 2110 | # else | ||
| 2111 | && a.arg[dp->arg_index].type == TYPE_WIDE_STRING | ||
| 2112 | # endif | ||
| 2113 | ) | ||
| 2114 | { | ||
| 2115 | /* The normal handling of the 's' directive below requires | ||
| 2116 | allocating a temporary buffer. The determination of its | ||
| 2117 | length (tmp_length), in the case when a precision is | ||
| 2118 | specified, below requires a conversion between a char[] | ||
| 2119 | string and a wchar_t[] wide string. It could be done, but | ||
| 2120 | we have no guarantee that the implementation of sprintf will | ||
| 2121 | use the exactly same algorithm. Without this guarantee, it | ||
| 2122 | is possible to have buffer overrun bugs. In order to avoid | ||
| 2123 | such bugs, we implement the entire processing of the 's' | ||
| 2124 | directive ourselves. */ | ||
| 2125 | int flags = dp->flags; | ||
| 2126 | int has_width; | ||
| 2127 | size_t width; | ||
| 2128 | int has_precision; | ||
| 2129 | size_t precision; | ||
| 2130 | |||
| 2131 | has_width = 0; | ||
| 2132 | width = 0; | ||
| 2133 | if (dp->width_start != dp->width_end) | ||
| 2134 | { | ||
| 2135 | if (dp->width_arg_index != ARG_NONE) | ||
| 2136 | { | ||
| 2137 | int arg; | ||
| 2138 | |||
| 2139 | if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) | ||
| 2140 | abort (); | ||
| 2141 | arg = a.arg[dp->width_arg_index].a.a_int; | ||
| 2142 | if (arg < 0) | ||
| 2143 | { | ||
| 2144 | /* "A negative field width is taken as a '-' flag | ||
| 2145 | followed by a positive field width." */ | ||
| 2146 | flags |= FLAG_LEFT; | ||
| 2147 | width = (unsigned int) (-arg); | ||
| 2148 | } | ||
| 2149 | else | ||
| 2150 | width = arg; | ||
| 2151 | } | ||
| 2152 | else | ||
| 2153 | { | ||
| 2154 | const FCHAR_T *digitp = dp->width_start; | ||
| 2155 | |||
| 2156 | do | ||
| 2157 | width = xsum (xtimes (width, 10), *digitp++ - '0'); | ||
| 2158 | while (digitp != dp->width_end); | ||
| 2159 | } | ||
| 2160 | has_width = 1; | ||
| 2161 | } | ||
| 2162 | |||
| 2163 | has_precision = 0; | ||
| 2164 | precision = 6; | ||
| 2165 | if (dp->precision_start != dp->precision_end) | ||
| 2166 | { | ||
| 2167 | if (dp->precision_arg_index != ARG_NONE) | ||
| 2168 | { | ||
| 2169 | int arg; | ||
| 2170 | |||
| 2171 | if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) | ||
| 2172 | abort (); | ||
| 2173 | arg = a.arg[dp->precision_arg_index].a.a_int; | ||
| 2174 | /* "A negative precision is taken as if the precision | ||
| 2175 | were omitted." */ | ||
| 2176 | if (arg >= 0) | ||
| 2177 | { | ||
| 2178 | precision = arg; | ||
| 2179 | has_precision = 1; | ||
| 2180 | } | ||
| 2181 | } | ||
| 2182 | else | ||
| 2183 | { | ||
| 2184 | const FCHAR_T *digitp = dp->precision_start + 1; | ||
| 2185 | |||
| 2186 | precision = 0; | ||
| 2187 | while (digitp != dp->precision_end) | ||
| 2188 | precision = xsum (xtimes (precision, 10), *digitp++ - '0'); | ||
| 2189 | has_precision = 1; | ||
| 2190 | } | ||
| 2191 | } | ||
| 2192 | |||
| 2193 | # if WIDE_CHAR_VERSION | ||
| 2194 | /* %s in vasnwprintf. See the specification of fwprintf. */ | ||
| 2195 | { | ||
| 2196 | const char *arg = a.arg[dp->arg_index].a.a_string; | ||
| 2197 | const char *arg_end; | ||
| 2198 | size_t characters; | ||
| 2199 | |||
| 2200 | if (has_precision) | ||
| 2201 | { | ||
| 2202 | /* Use only as many bytes as needed to produce PRECISION | ||
| 2203 | wide characters, from the left. */ | ||
| 2204 | # if HAVE_MBRTOWC | ||
| 2205 | mbstate_t state; | ||
| 2206 | memset (&state, '\0', sizeof (mbstate_t)); | ||
| 2207 | # endif | ||
| 2208 | arg_end = arg; | ||
| 2209 | characters = 0; | ||
| 2210 | for (; precision > 0; precision--) | ||
| 2211 | { | ||
| 2212 | int count; | ||
| 2213 | # if HAVE_MBRTOWC | ||
| 2214 | count = mbrlen (arg_end, MB_CUR_MAX, &state); | ||
| 2215 | # else | ||
| 2216 | count = mblen (arg_end, MB_CUR_MAX); | ||
| 2217 | # endif | ||
| 2218 | if (count == 0) | ||
| 2219 | /* Found the terminating NUL. */ | ||
| 2220 | break; | ||
| 2221 | if (count < 0) | ||
| 2222 | { | ||
| 2223 | /* Invalid or incomplete multibyte character. */ | ||
| 2224 | if (!(result == resultbuf || result == NULL)) | ||
| 2225 | free (result); | ||
| 2226 | if (buf_malloced != NULL) | ||
| 2227 | free (buf_malloced); | ||
| 2228 | CLEANUP (); | ||
| 2229 | errno = EILSEQ; | ||
| 2230 | return NULL; | ||
| 2231 | } | ||
| 2232 | arg_end += count; | ||
| 2233 | characters++; | ||
| 2234 | } | ||
| 2235 | } | ||
| 2236 | else if (has_width) | ||
| 2237 | { | ||
| 2238 | /* Use the entire string, and count the number of wide | ||
| 2239 | characters. */ | ||
| 2240 | # if HAVE_MBRTOWC | ||
| 2241 | mbstate_t state; | ||
| 2242 | memset (&state, '\0', sizeof (mbstate_t)); | ||
| 2243 | # endif | ||
| 2244 | arg_end = arg; | ||
| 2245 | characters = 0; | ||
| 2246 | for (;;) | ||
| 2247 | { | ||
| 2248 | int count; | ||
| 2249 | # if HAVE_MBRTOWC | ||
| 2250 | count = mbrlen (arg_end, MB_CUR_MAX, &state); | ||
| 2251 | # else | ||
| 2252 | count = mblen (arg_end, MB_CUR_MAX); | ||
| 2253 | # endif | ||
| 2254 | if (count == 0) | ||
| 2255 | /* Found the terminating NUL. */ | ||
| 2256 | break; | ||
| 2257 | if (count < 0) | ||
| 2258 | { | ||
| 2259 | /* Invalid or incomplete multibyte character. */ | ||
| 2260 | if (!(result == resultbuf || result == NULL)) | ||
| 2261 | free (result); | ||
| 2262 | if (buf_malloced != NULL) | ||
| 2263 | free (buf_malloced); | ||
| 2264 | CLEANUP (); | ||
| 2265 | errno = EILSEQ; | ||
| 2266 | return NULL; | ||
| 2267 | } | ||
| 2268 | arg_end += count; | ||
| 2269 | characters++; | ||
| 2270 | } | ||
| 2271 | } | ||
| 2272 | else | ||
| 2273 | { | ||
| 2274 | /* Use the entire string. */ | ||
| 2275 | arg_end = arg + strlen (arg); | ||
| 2276 | /* The number of characters doesn't matter. */ | ||
| 2277 | characters = 0; | ||
| 2278 | } | ||
| 2279 | |||
| 2280 | if (has_width && width > characters | ||
| 2281 | && !(dp->flags & FLAG_LEFT)) | ||
| 2282 | { | ||
| 2283 | size_t n = width - characters; | ||
| 2284 | ENSURE_ALLOCATION (xsum (length, n)); | ||
| 2285 | DCHAR_SET (result + length, ' ', n); | ||
| 2286 | length += n; | ||
| 2287 | } | ||
| 2288 | |||
| 2289 | if (has_precision || has_width) | ||
| 2290 | { | ||
| 2291 | /* We know the number of wide characters in advance. */ | ||
| 2292 | size_t remaining; | ||
| 2293 | # if HAVE_MBRTOWC | ||
| 2294 | mbstate_t state; | ||
| 2295 | memset (&state, '\0', sizeof (mbstate_t)); | ||
| 2296 | # endif | ||
| 2297 | ENSURE_ALLOCATION (xsum (length, characters)); | ||
| 2298 | for (remaining = characters; remaining > 0; remaining--) | ||
| 2299 | { | ||
| 2300 | wchar_t wc; | ||
| 2301 | int count; | ||
| 2302 | # if HAVE_MBRTOWC | ||
| 2303 | count = mbrtowc (&wc, arg, arg_end - arg, &state); | ||
| 2304 | # else | ||
| 2305 | count = mbtowc (&wc, arg, arg_end - arg); | ||
| 2306 | # endif | ||
| 2307 | if (count <= 0) | ||
| 2308 | /* mbrtowc not consistent with mbrlen, or mbtowc | ||
| 2309 | not consistent with mblen. */ | ||
| 2310 | abort (); | ||
| 2311 | result[length++] = wc; | ||
| 2312 | arg += count; | ||
| 2313 | } | ||
| 2314 | if (!(arg == arg_end)) | ||
| 2315 | abort (); | ||
| 2316 | } | ||
| 2317 | else | ||
| 2318 | { | ||
| 2319 | # if HAVE_MBRTOWC | ||
| 2320 | mbstate_t state; | ||
| 2321 | memset (&state, '\0', sizeof (mbstate_t)); | ||
| 2322 | # endif | ||
| 2323 | while (arg < arg_end) | ||
| 2324 | { | ||
| 2325 | wchar_t wc; | ||
| 2326 | int count; | ||
| 2327 | # if HAVE_MBRTOWC | ||
| 2328 | count = mbrtowc (&wc, arg, arg_end - arg, &state); | ||
| 2329 | # else | ||
| 2330 | count = mbtowc (&wc, arg, arg_end - arg); | ||
| 2331 | # endif | ||
| 2332 | if (count <= 0) | ||
| 2333 | /* mbrtowc not consistent with mbrlen, or mbtowc | ||
| 2334 | not consistent with mblen. */ | ||
| 2335 | abort (); | ||
| 2336 | ENSURE_ALLOCATION (xsum (length, 1)); | ||
| 2337 | result[length++] = wc; | ||
| 2338 | arg += count; | ||
| 2339 | } | ||
| 2340 | } | ||
| 2341 | |||
| 2342 | if (has_width && width > characters | ||
| 2343 | && (dp->flags & FLAG_LEFT)) | ||
| 2344 | { | ||
| 2345 | size_t n = width - characters; | ||
| 2346 | ENSURE_ALLOCATION (xsum (length, n)); | ||
| 2347 | DCHAR_SET (result + length, ' ', n); | ||
| 2348 | length += n; | ||
| 2349 | } | ||
| 2350 | } | ||
| 2351 | # else | ||
| 2352 | /* %ls in vasnprintf. See the specification of fprintf. */ | ||
| 2353 | { | ||
| 2354 | const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string; | ||
| 2355 | const wchar_t *arg_end; | ||
| 2356 | size_t characters; | ||
| 2357 | # if !DCHAR_IS_TCHAR | ||
| 2358 | /* This code assumes that TCHAR_T is 'char'. */ | ||
| 2359 | typedef int TCHAR_T_verify[2 * (sizeof (TCHAR_T) == 1) - 1]; | ||
| 2360 | TCHAR_T *tmpsrc; | ||
| 2361 | DCHAR_T *tmpdst; | ||
| 2362 | size_t tmpdst_len; | ||
| 2363 | # endif | ||
| 2364 | size_t w; | ||
| 2365 | |||
| 2366 | if (has_precision) | ||
| 2367 | { | ||
| 2368 | /* Use only as many wide characters as needed to produce | ||
| 2369 | at most PRECISION bytes, from the left. */ | ||
| 2370 | # if HAVE_WCRTOMB | ||
| 2371 | mbstate_t state; | ||
| 2372 | memset (&state, '\0', sizeof (mbstate_t)); | ||
| 2373 | # endif | ||
| 2374 | arg_end = arg; | ||
| 2375 | characters = 0; | ||
| 2376 | while (precision > 0) | ||
| 2377 | { | ||
| 2378 | char buf[64]; /* Assume MB_CUR_MAX <= 64. */ | ||
| 2379 | int count; | ||
| 2380 | |||
| 2381 | if (*arg_end == 0) | ||
| 2382 | /* Found the terminating null wide character. */ | ||
| 2383 | break; | ||
| 2384 | # if HAVE_WCRTOMB | ||
| 2385 | count = wcrtomb (buf, *arg_end, &state); | ||
| 2386 | # else | ||
| 2387 | count = wctomb (buf, *arg_end); | ||
| 2388 | # endif | ||
| 2389 | if (count < 0) | ||
| 2390 | { | ||
| 2391 | /* Cannot convert. */ | ||
| 2392 | if (!(result == resultbuf || result == NULL)) | ||
| 2393 | free (result); | ||
| 2394 | if (buf_malloced != NULL) | ||
| 2395 | free (buf_malloced); | ||
| 2396 | CLEANUP (); | ||
| 2397 | errno = EILSEQ; | ||
| 2398 | return NULL; | ||
| 2399 | } | ||
| 2400 | if (precision < count) | ||
| 2401 | break; | ||
| 2402 | arg_end++; | ||
| 2403 | characters += count; | ||
| 2404 | precision -= count; | ||
| 2405 | } | ||
| 2406 | } | ||
| 2407 | # if DCHAR_IS_TCHAR | ||
| 2408 | else if (has_width) | ||
| 2409 | # else | ||
| 2410 | else | ||
| 2411 | # endif | ||
| 2412 | { | ||
| 2413 | /* Use the entire string, and count the number of | ||
| 2414 | bytes. */ | ||
| 2415 | # if HAVE_WCRTOMB | ||
| 2416 | mbstate_t state; | ||
| 2417 | memset (&state, '\0', sizeof (mbstate_t)); | ||
| 2418 | # endif | ||
| 2419 | arg_end = arg; | ||
| 2420 | characters = 0; | ||
| 2421 | for (;;) | ||
| 2422 | { | ||
| 2423 | char buf[64]; /* Assume MB_CUR_MAX <= 64. */ | ||
| 2424 | int count; | ||
| 2425 | |||
| 2426 | if (*arg_end == 0) | ||
| 2427 | /* Found the terminating null wide character. */ | ||
| 2428 | break; | ||
| 2429 | # if HAVE_WCRTOMB | ||
| 2430 | count = wcrtomb (buf, *arg_end, &state); | ||
| 2431 | # else | ||
| 2432 | count = wctomb (buf, *arg_end); | ||
| 2433 | # endif | ||
| 2434 | if (count < 0) | ||
| 2435 | { | ||
| 2436 | /* Cannot convert. */ | ||
| 2437 | if (!(result == resultbuf || result == NULL)) | ||
| 2438 | free (result); | ||
| 2439 | if (buf_malloced != NULL) | ||
| 2440 | free (buf_malloced); | ||
| 2441 | CLEANUP (); | ||
| 2442 | errno = EILSEQ; | ||
| 2443 | return NULL; | ||
| 2444 | } | ||
| 2445 | arg_end++; | ||
| 2446 | characters += count; | ||
| 2447 | } | ||
| 2448 | } | ||
| 2449 | # if DCHAR_IS_TCHAR | ||
| 2450 | else | ||
| 2451 | { | ||
| 2452 | /* Use the entire string. */ | ||
| 2453 | arg_end = arg + local_wcslen (arg); | ||
| 2454 | /* The number of bytes doesn't matter. */ | ||
| 2455 | characters = 0; | ||
| 2456 | } | ||
| 2457 | # endif | ||
| 2458 | |||
| 2459 | # if !DCHAR_IS_TCHAR | ||
| 2460 | /* Convert the string into a piece of temporary memory. */ | ||
| 2461 | tmpsrc = (TCHAR_T *) malloc (characters * sizeof (TCHAR_T)); | ||
| 2462 | if (tmpsrc == NULL) | ||
| 2463 | goto out_of_memory; | ||
| 2464 | { | ||
| 2465 | TCHAR_T *tmpptr = tmpsrc; | ||
| 2466 | size_t remaining; | ||
| 2467 | # if HAVE_WCRTOMB | ||
| 2468 | mbstate_t state; | ||
| 2469 | memset (&state, '\0', sizeof (mbstate_t)); | ||
| 2470 | # endif | ||
| 2471 | for (remaining = characters; remaining > 0; ) | ||
| 2472 | { | ||
| 2473 | char buf[64]; /* Assume MB_CUR_MAX <= 64. */ | ||
| 2474 | int count; | ||
| 2475 | |||
| 2476 | if (*arg == 0) | ||
| 2477 | abort (); | ||
| 2478 | # if HAVE_WCRTOMB | ||
| 2479 | count = wcrtomb (buf, *arg, &state); | ||
| 2480 | # else | ||
| 2481 | count = wctomb (buf, *arg); | ||
| 2482 | # endif | ||
| 2483 | if (count <= 0) | ||
| 2484 | /* Inconsistency. */ | ||
| 2485 | abort (); | ||
| 2486 | memcpy (tmpptr, buf, count); | ||
| 2487 | tmpptr += count; | ||
| 2488 | arg++; | ||
| 2489 | remaining -= count; | ||
| 2490 | } | ||
| 2491 | if (!(arg == arg_end)) | ||
| 2492 | abort (); | ||
| 2493 | } | ||
| 2494 | |||
| 2495 | /* Convert from TCHAR_T[] to DCHAR_T[]. */ | ||
| 2496 | tmpdst = | ||
| 2497 | DCHAR_CONV_FROM_ENCODING (locale_charset (), | ||
| 2498 | iconveh_question_mark, | ||
| 2499 | tmpsrc, characters, | ||
| 2500 | NULL, | ||
| 2501 | NULL, &tmpdst_len); | ||
| 2502 | if (tmpdst == NULL) | ||
| 2503 | { | ||
| 2504 | int saved_errno = errno; | ||
| 2505 | free (tmpsrc); | ||
| 2506 | if (!(result == resultbuf || result == NULL)) | ||
| 2507 | free (result); | ||
| 2508 | if (buf_malloced != NULL) | ||
| 2509 | free (buf_malloced); | ||
| 2510 | CLEANUP (); | ||
| 2511 | errno = saved_errno; | ||
| 2512 | return NULL; | ||
| 2513 | } | ||
| 2514 | free (tmpsrc); | ||
| 2515 | # endif | ||
| 2516 | |||
| 2517 | if (has_width) | ||
| 2518 | { | ||
| 2519 | # if ENABLE_UNISTDIO | ||
| 2520 | /* Outside POSIX, it's preferrable to compare the width | ||
| 2521 | against the number of _characters_ of the converted | ||
| 2522 | value. */ | ||
| 2523 | w = DCHAR_MBSNLEN (result + length, characters); | ||
| 2524 | # else | ||
| 2525 | /* The width is compared against the number of _bytes_ | ||
| 2526 | of the converted value, says POSIX. */ | ||
| 2527 | w = characters; | ||
| 2528 | # endif | ||
| 2529 | } | ||
| 2530 | else | ||
| 2531 | /* w doesn't matter. */ | ||
| 2532 | w = 0; | ||
| 2533 | |||
| 2534 | if (has_width && width > w | ||
| 2535 | && !(dp->flags & FLAG_LEFT)) | ||
| 2536 | { | ||
| 2537 | size_t n = width - w; | ||
| 2538 | ENSURE_ALLOCATION (xsum (length, n)); | ||
| 2539 | DCHAR_SET (result + length, ' ', n); | ||
| 2540 | length += n; | ||
| 2541 | } | ||
| 2542 | |||
| 2543 | # if DCHAR_IS_TCHAR | ||
| 2544 | if (has_precision || has_width) | ||
| 2545 | { | ||
| 2546 | /* We know the number of bytes in advance. */ | ||
| 2547 | size_t remaining; | ||
| 2548 | # if HAVE_WCRTOMB | ||
| 2549 | mbstate_t state; | ||
| 2550 | memset (&state, '\0', sizeof (mbstate_t)); | ||
| 2551 | # endif | ||
| 2552 | ENSURE_ALLOCATION (xsum (length, characters)); | ||
| 2553 | for (remaining = characters; remaining > 0; ) | ||
| 2554 | { | ||
| 2555 | char buf[64]; /* Assume MB_CUR_MAX <= 64. */ | ||
| 2556 | int count; | ||
| 2557 | |||
| 2558 | if (*arg == 0) | ||
| 2559 | abort (); | ||
| 2560 | # if HAVE_WCRTOMB | ||
| 2561 | count = wcrtomb (buf, *arg, &state); | ||
| 2562 | # else | ||
| 2563 | count = wctomb (buf, *arg); | ||
| 2564 | # endif | ||
| 2565 | if (count <= 0) | ||
| 2566 | /* Inconsistency. */ | ||
| 2567 | abort (); | ||
| 2568 | memcpy (result + length, buf, count); | ||
| 2569 | length += count; | ||
| 2570 | arg++; | ||
| 2571 | remaining -= count; | ||
| 2572 | } | ||
| 2573 | if (!(arg == arg_end)) | ||
| 2574 | abort (); | ||
| 2575 | } | ||
| 2576 | else | ||
| 2577 | { | ||
| 2578 | # if HAVE_WCRTOMB | ||
| 2579 | mbstate_t state; | ||
| 2580 | memset (&state, '\0', sizeof (mbstate_t)); | ||
| 2581 | # endif | ||
| 2582 | while (arg < arg_end) | ||
| 2583 | { | ||
| 2584 | char buf[64]; /* Assume MB_CUR_MAX <= 64. */ | ||
| 2585 | int count; | ||
| 2586 | |||
| 2587 | if (*arg == 0) | ||
| 2588 | abort (); | ||
| 2589 | # if HAVE_WCRTOMB | ||
| 2590 | count = wcrtomb (buf, *arg, &state); | ||
| 2591 | # else | ||
| 2592 | count = wctomb (buf, *arg); | ||
| 2593 | # endif | ||
| 2594 | if (count <= 0) | ||
| 2595 | /* Inconsistency. */ | ||
| 2596 | abort (); | ||
| 2597 | ENSURE_ALLOCATION (xsum (length, count)); | ||
| 2598 | memcpy (result + length, buf, count); | ||
| 2599 | length += count; | ||
| 2600 | arg++; | ||
| 2601 | } | ||
| 2602 | } | ||
| 2603 | # else | ||
| 2604 | ENSURE_ALLOCATION (xsum (length, tmpdst_len)); | ||
| 2605 | DCHAR_CPY (result + length, tmpdst, tmpdst_len); | ||
| 2606 | free (tmpdst); | ||
| 2607 | length += tmpdst_len; | ||
| 2608 | # endif | ||
| 2609 | |||
| 2610 | if (has_width && width > w | ||
| 2611 | && (dp->flags & FLAG_LEFT)) | ||
| 2612 | { | ||
| 2613 | size_t n = width - w; | ||
| 2614 | ENSURE_ALLOCATION (xsum (length, n)); | ||
| 2615 | DCHAR_SET (result + length, ' ', n); | ||
| 2616 | length += n; | ||
| 2617 | } | ||
| 2618 | } | ||
| 2619 | } | ||
| 2620 | # endif | ||
| 2621 | #endif | ||
| 2069 | #if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL | 2622 | #if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL |
| 2070 | else if ((dp->conversion == 'a' || dp->conversion == 'A') | 2623 | else if ((dp->conversion == 'a' || dp->conversion == 'A') |
| 2071 | # if !(NEED_PRINTF_DIRECTIVE_A || (NEED_PRINTF_LONG_DOUBLE && NEED_PRINTF_DOUBLE)) | 2624 | # if !(NEED_PRINTF_DIRECTIVE_A || (NEED_PRINTF_LONG_DOUBLE && NEED_PRINTF_DOUBLE)) |
| @@ -4032,16 +4585,64 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 4032 | # if HAVE_WCHAR_T | 4585 | # if HAVE_WCHAR_T |
| 4033 | if (type == TYPE_WIDE_STRING) | 4586 | if (type == TYPE_WIDE_STRING) |
| 4034 | { | 4587 | { |
| 4035 | tmp_length = | 4588 | # if WIDE_CHAR_VERSION |
| 4036 | local_wcslen (a.arg[dp->arg_index].a.a_wide_string); | 4589 | /* ISO C says about %ls in fwprintf: |
| 4037 | 4590 | "If the precision is not specified or is greater | |
| 4038 | # if !WIDE_CHAR_VERSION | 4591 | than the size of the array, the array shall |
| 4039 | tmp_length = xtimes (tmp_length, MB_CUR_MAX); | 4592 | contain a null wide character." |
| 4593 | So if there is a precision, we must not use | ||
| 4594 | wcslen. */ | ||
| 4595 | const wchar_t *arg = | ||
| 4596 | a.arg[dp->arg_index].a.a_wide_string; | ||
| 4597 | |||
| 4598 | if (has_precision) | ||
| 4599 | tmp_length = local_wcsnlen (arg, precision); | ||
| 4600 | else | ||
| 4601 | tmp_length = local_wcslen (arg); | ||
| 4602 | # else | ||
| 4603 | /* ISO C says about %ls in fprintf: | ||
| 4604 | "If a precision is specified, no more than that | ||
| 4605 | many bytes are written (including shift | ||
| 4606 | sequences, if any), and the array shall contain | ||
| 4607 | a null wide character if, to equal the | ||
| 4608 | multibyte character sequence length given by | ||
| 4609 | the precision, the function would need to | ||
| 4610 | access a wide character one past the end of the | ||
| 4611 | array." | ||
| 4612 | So if there is a precision, we must not use | ||
| 4613 | wcslen. */ | ||
| 4614 | /* This case has already been handled above. */ | ||
| 4615 | abort (); | ||
| 4040 | # endif | 4616 | # endif |
| 4041 | } | 4617 | } |
| 4042 | else | 4618 | else |
| 4043 | # endif | 4619 | # endif |
| 4044 | tmp_length = strlen (a.arg[dp->arg_index].a.a_string); | 4620 | { |
| 4621 | # if WIDE_CHAR_VERSION | ||
| 4622 | /* ISO C says about %s in fwprintf: | ||
| 4623 | "If the precision is not specified or is greater | ||
| 4624 | than the size of the converted array, the | ||
| 4625 | converted array shall contain a null wide | ||
| 4626 | character." | ||
| 4627 | So if there is a precision, we must not use | ||
| 4628 | strlen. */ | ||
| 4629 | /* This case has already been handled above. */ | ||
| 4630 | abort (); | ||
| 4631 | # else | ||
| 4632 | /* ISO C says about %s in fprintf: | ||
| 4633 | "If the precision is not specified or greater | ||
| 4634 | than the size of the array, the array shall | ||
| 4635 | contain a null character." | ||
| 4636 | So if there is a precision, we must not use | ||
| 4637 | strlen. */ | ||
| 4638 | const char *arg = a.arg[dp->arg_index].a.a_string; | ||
| 4639 | |||
| 4640 | if (has_precision) | ||
| 4641 | tmp_length = local_strnlen (arg, precision); | ||
| 4642 | else | ||
| 4643 | tmp_length = strlen (arg); | ||
| 4644 | # endif | ||
| 4645 | } | ||
| 4045 | break; | 4646 | break; |
| 4046 | 4647 | ||
| 4047 | case 'p': | 4648 | case 'p': |
| @@ -4614,14 +5215,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, | |||
| 4614 | # else | 5215 | # else |
| 4615 | tmpsrc = tmp; | 5216 | tmpsrc = tmp; |
| 4616 | # endif | 5217 | # endif |
| 4617 | tmpdst = NULL; | 5218 | tmpdst = |
| 4618 | tmpdst_len = 0; | 5219 | DCHAR_CONV_FROM_ENCODING (locale_charset (), |
| 4619 | if (DCHAR_CONV_FROM_ENCODING (locale_charset (), | 5220 | iconveh_question_mark, |
| 4620 | iconveh_question_mark, | 5221 | tmpsrc, count, |
| 4621 | tmpsrc, count, | 5222 | NULL, |
| 4622 | NULL, | 5223 | NULL, &tmpdst_len); |
| 4623 | &tmpdst, &tmpdst_len) | 5224 | if (tmpdst == NULL) |
| 4624 | < 0) | ||
| 4625 | { | 5225 | { |
| 4626 | int saved_errno = errno; | 5226 | int saved_errno = errno; |
| 4627 | if (!(result == resultbuf || result == NULL)) | 5227 | if (!(result == resultbuf || result == NULL)) |
