1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/io/uprntf_p.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1589 @@ 1.4 +/* 1.5 +****************************************************************************** 1.6 +* 1.7 +* Copyright (C) 1998-2011, International Business Machines 1.8 +* Corporation and others. All Rights Reserved. 1.9 +* 1.10 +****************************************************************************** 1.11 +* 1.12 +* File uprntf_p.c 1.13 +* 1.14 +* Modification History: 1.15 +* 1.16 +* Date Name Description 1.17 +* 11/23/98 stephen Creation. 1.18 +* 03/12/99 stephen Modified for new C API. 1.19 +* 08/07/2003 george Reunify printf implementations 1.20 +****************************************************************************** 1.21 +*/ 1.22 + 1.23 +#include "unicode/utypes.h" 1.24 + 1.25 +#if !UCONFIG_NO_FORMATTING 1.26 + 1.27 +#include "unicode/ustring.h" 1.28 +#include "unicode/utf16.h" 1.29 +#include "uprintf.h" 1.30 +#include "ufmt_cmn.h" 1.31 +#include "cmemory.h" 1.32 +#include "putilimp.h" 1.33 + 1.34 +/* ANSI style formatting */ 1.35 +/* Use US-ASCII characters only for formatting */ 1.36 + 1.37 +/* % */ 1.38 +#define UFMT_SIMPLE_PERCENT {ufmt_simple_percent, u_printf_simple_percent_handler} 1.39 +/* s */ 1.40 +#define UFMT_STRING {ufmt_string, u_printf_string_handler} 1.41 +/* c */ 1.42 +#define UFMT_CHAR {ufmt_char, u_printf_char_handler} 1.43 +/* d, i */ 1.44 +#define UFMT_INT {ufmt_int, u_printf_integer_handler} 1.45 +/* u */ 1.46 +#define UFMT_UINT {ufmt_int, u_printf_uinteger_handler} 1.47 +/* o */ 1.48 +#define UFMT_OCTAL {ufmt_int, u_printf_octal_handler} 1.49 +/* x, X */ 1.50 +#define UFMT_HEX {ufmt_int, u_printf_hex_handler} 1.51 +/* f */ 1.52 +#define UFMT_DOUBLE {ufmt_double, u_printf_double_handler} 1.53 +/* e, E */ 1.54 +#define UFMT_SCIENTIFIC {ufmt_double, u_printf_scientific_handler} 1.55 +/* g, G */ 1.56 +#define UFMT_SCIDBL {ufmt_double, u_printf_scidbl_handler} 1.57 +/* n */ 1.58 +#define UFMT_COUNT {ufmt_count, u_printf_count_handler} 1.59 + 1.60 +/* non-ANSI extensions */ 1.61 +/* Use US-ASCII characters only for formatting */ 1.62 + 1.63 +/* p */ 1.64 +#define UFMT_POINTER {ufmt_pointer, u_printf_pointer_handler} 1.65 +/* V */ 1.66 +#define UFMT_SPELLOUT {ufmt_double, u_printf_spellout_handler} 1.67 +/* P */ 1.68 +#define UFMT_PERCENT {ufmt_double, u_printf_percent_handler} 1.69 +/* C K is old format */ 1.70 +#define UFMT_UCHAR {ufmt_uchar, u_printf_uchar_handler} 1.71 +/* S U is old format */ 1.72 +#define UFMT_USTRING {ufmt_ustring, u_printf_ustring_handler} 1.73 + 1.74 + 1.75 +#define UFMT_EMPTY {ufmt_empty, NULL} 1.76 + 1.77 +/** 1.78 + * A u_printf handler function. 1.79 + * A u_printf handler is responsible for handling a single u_printf 1.80 + * format specification, for example 'd' or 's'. 1.81 + * @param stream The UFILE to which to write output. 1.82 + * @param info A pointer to a <TT>u_printf_spec_info</TT> struct containing 1.83 + * information on the format specification. 1.84 + * @param args A pointer to the argument data 1.85 + * @return The number of Unicode characters written to <TT>stream</TT>. 1.86 + */ 1.87 +typedef int32_t U_EXPORT2 1.88 +u_printf_handler(const u_printf_stream_handler *handler, 1.89 + 1.90 + void *context, 1.91 + ULocaleBundle *formatBundle, 1.92 + const u_printf_spec_info *info, 1.93 + const ufmt_args *args); 1.94 + 1.95 +typedef struct u_printf_info { 1.96 + ufmt_type_info info; 1.97 + u_printf_handler *handler; 1.98 +} u_printf_info; 1.99 + 1.100 +/** 1.101 + * Struct encapsulating a single uprintf format specification. 1.102 + */ 1.103 +typedef struct u_printf_spec { 1.104 + u_printf_spec_info fInfo; /* Information on this spec */ 1.105 + int32_t fWidthPos; /* Position of width in arg list */ 1.106 + int32_t fPrecisionPos; /* Position of precision in arg list */ 1.107 + int32_t fArgPos; /* Position of data in arg list */ 1.108 +} u_printf_spec; 1.109 + 1.110 +#define UPRINTF_NUM_FMT_HANDLERS 108 1.111 + 1.112 +/* We do not use handlers for 0-0x1f */ 1.113 +#define UPRINTF_BASE_FMT_HANDLERS 0x20 1.114 + 1.115 +/* buffer size for formatting */ 1.116 +#define UPRINTF_BUFFER_SIZE 1024 1.117 +#define UPRINTF_SYMBOL_BUFFER_SIZE 8 1.118 + 1.119 +static const UChar gNullStr[] = {0x28, 0x6E, 0x75, 0x6C, 0x6C, 0x29, 0}; /* "(null)" */ 1.120 +static const UChar gSpaceStr[] = {0x20, 0}; /* " " */ 1.121 + 1.122 +/* Sets the sign of a format based on u_printf_spec_info */ 1.123 +/* TODO: Is setting the prefix symbol to a positive sign a good idea in all locales? */ 1.124 +static void 1.125 +u_printf_set_sign(UNumberFormat *format, 1.126 + const u_printf_spec_info *info, 1.127 + UChar *prefixBuffer, 1.128 + int32_t *prefixBufLen, 1.129 + UErrorCode *status) 1.130 +{ 1.131 + if(info->fShowSign) { 1.132 + *prefixBufLen = unum_getTextAttribute(format, 1.133 + UNUM_POSITIVE_PREFIX, 1.134 + prefixBuffer, 1.135 + *prefixBufLen, 1.136 + status); 1.137 + if (info->fSpace) { 1.138 + /* Setting UNUM_PLUS_SIGN_SYMBOL affects the exponent too. */ 1.139 + /* unum_setSymbol(format, UNUM_PLUS_SIGN_SYMBOL, gSpaceStr, 1, &status); */ 1.140 + unum_setTextAttribute(format, UNUM_POSITIVE_PREFIX, gSpaceStr, 1, status); 1.141 + } 1.142 + else { 1.143 + UChar plusSymbol[UPRINTF_SYMBOL_BUFFER_SIZE]; 1.144 + int32_t symbolLen; 1.145 + 1.146 + symbolLen = unum_getSymbol(format, 1.147 + UNUM_PLUS_SIGN_SYMBOL, 1.148 + plusSymbol, 1.149 + sizeof(plusSymbol)/sizeof(*plusSymbol), 1.150 + status); 1.151 + unum_setTextAttribute(format, 1.152 + UNUM_POSITIVE_PREFIX, 1.153 + plusSymbol, 1.154 + symbolLen, 1.155 + status); 1.156 + } 1.157 + } 1.158 + else { 1.159 + *prefixBufLen = 0; 1.160 + } 1.161 +} 1.162 + 1.163 +static void 1.164 +u_printf_reset_sign(UNumberFormat *format, 1.165 + const u_printf_spec_info *info, 1.166 + UChar *prefixBuffer, 1.167 + int32_t *prefixBufLen, 1.168 + UErrorCode *status) 1.169 +{ 1.170 + if(info->fShowSign) { 1.171 + unum_setTextAttribute(format, 1.172 + UNUM_POSITIVE_PREFIX, 1.173 + prefixBuffer, 1.174 + *prefixBufLen, 1.175 + status); 1.176 + } 1.177 +} 1.178 + 1.179 + 1.180 +/* handle a '%' */ 1.181 +static int32_t 1.182 +u_printf_simple_percent_handler(const u_printf_stream_handler *handler, 1.183 + void *context, 1.184 + ULocaleBundle *formatBundle, 1.185 + const u_printf_spec_info *info, 1.186 + const ufmt_args *args) 1.187 +{ 1.188 + static const UChar PERCENT[] = { UP_PERCENT }; 1.189 + 1.190 + /* put a single '%' onto the output */ 1.191 + return handler->write(context, PERCENT, 1); 1.192 +} 1.193 + 1.194 +/* handle 's' */ 1.195 +static int32_t 1.196 +u_printf_string_handler(const u_printf_stream_handler *handler, 1.197 + void *context, 1.198 + ULocaleBundle *formatBundle, 1.199 + const u_printf_spec_info *info, 1.200 + const ufmt_args *args) 1.201 +{ 1.202 + UChar *s; 1.203 + UChar buffer[UFMT_DEFAULT_BUFFER_SIZE]; 1.204 + int32_t len, written; 1.205 + int32_t argSize; 1.206 + const char *arg = (const char*)(args[0].ptrValue); 1.207 + 1.208 + /* convert from the default codepage to Unicode */ 1.209 + if (arg) { 1.210 + argSize = (int32_t)strlen(arg) + 1; 1.211 + if (argSize >= MAX_UCHAR_BUFFER_SIZE(buffer)) { 1.212 + s = ufmt_defaultCPToUnicode(arg, argSize, 1.213 + (UChar *)uprv_malloc(MAX_UCHAR_BUFFER_NEEDED(argSize)), 1.214 + MAX_UCHAR_BUFFER_NEEDED(argSize)); 1.215 + if(s == NULL) { 1.216 + return 0; 1.217 + } 1.218 + } 1.219 + else { 1.220 + s = ufmt_defaultCPToUnicode(arg, argSize, buffer, 1.221 + sizeof(buffer)/sizeof(UChar)); 1.222 + } 1.223 + } 1.224 + else { 1.225 + s = (UChar *)gNullStr; 1.226 + } 1.227 + len = u_strlen(s); 1.228 + 1.229 + /* width = minimum # of characters to write */ 1.230 + /* precision = maximum # of characters to write */ 1.231 + if (info->fPrecision != -1 && info->fPrecision < len) { 1.232 + len = info->fPrecision; 1.233 + } 1.234 + 1.235 + written = handler->pad_and_justify(context, info, s, len); 1.236 + 1.237 + /* clean up */ 1.238 + if (gNullStr != s && buffer != s) { 1.239 + uprv_free(s); 1.240 + } 1.241 + 1.242 + return written; 1.243 +} 1.244 + 1.245 +static int32_t 1.246 +u_printf_char_handler(const u_printf_stream_handler *handler, 1.247 + void *context, 1.248 + ULocaleBundle *formatBundle, 1.249 + const u_printf_spec_info *info, 1.250 + const ufmt_args *args) 1.251 +{ 1.252 + UChar s[U16_MAX_LENGTH+1]; 1.253 + int32_t len = 1, written; 1.254 + unsigned char arg = (unsigned char)(args[0].int64Value); 1.255 + 1.256 + /* convert from default codepage to Unicode */ 1.257 + ufmt_defaultCPToUnicode((const char *)&arg, 2, s, sizeof(s)/sizeof(UChar)); 1.258 + 1.259 + /* Remember that this may be an MBCS character */ 1.260 + if (arg != 0) { 1.261 + len = u_strlen(s); 1.262 + } 1.263 + 1.264 + /* width = minimum # of characters to write */ 1.265 + /* precision = maximum # of characters to write */ 1.266 + /* precision is ignored when handling a char */ 1.267 + 1.268 + written = handler->pad_and_justify(context, info, s, len); 1.269 + 1.270 + return written; 1.271 +} 1.272 + 1.273 +static int32_t 1.274 +u_printf_double_handler(const u_printf_stream_handler *handler, 1.275 + void *context, 1.276 + ULocaleBundle *formatBundle, 1.277 + const u_printf_spec_info *info, 1.278 + const ufmt_args *args) 1.279 +{ 1.280 + double num = (double) (args[0].doubleValue); 1.281 + UNumberFormat *format; 1.282 + UChar result[UPRINTF_BUFFER_SIZE]; 1.283 + UChar prefixBuffer[UPRINTF_BUFFER_SIZE]; 1.284 + int32_t prefixBufferLen = sizeof(prefixBuffer); 1.285 + int32_t minDecimalDigits; 1.286 + int32_t maxDecimalDigits; 1.287 + int32_t resultLen; 1.288 + UErrorCode status = U_ZERO_ERROR; 1.289 + 1.290 + prefixBuffer[0] = 0; 1.291 + 1.292 + /* mask off any necessary bits */ 1.293 + /* if(! info->fIsLongDouble) 1.294 + num &= DBL_MAX;*/ 1.295 + 1.296 + /* get the formatter */ 1.297 + format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL); 1.298 + 1.299 + /* handle error */ 1.300 + if(format == 0) 1.301 + return 0; 1.302 + 1.303 + /* save the formatter's state */ 1.304 + minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS); 1.305 + maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS); 1.306 + 1.307 + /* set the appropriate flags and number of decimal digits on the formatter */ 1.308 + if(info->fPrecision != -1) { 1.309 + /* set the # of decimal digits */ 1.310 + unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision); 1.311 + } 1.312 + else if(info->fAlt) { 1.313 + /* '#' means always show decimal point */ 1.314 + /* copy of printf behavior on Solaris - '#' shows 6 digits */ 1.315 + unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); 1.316 + } 1.317 + else { 1.318 + /* # of decimal digits is 6 if precision not specified regardless of locale */ 1.319 + unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); 1.320 + } 1.321 + 1.322 + /* set whether to show the sign */ 1.323 + if (info->fShowSign) { 1.324 + u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status); 1.325 + } 1.326 + 1.327 + /* format the number */ 1.328 + resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status); 1.329 + 1.330 + if (U_FAILURE(status)) { 1.331 + resultLen = 0; 1.332 + } 1.333 + 1.334 + /* restore the number format */ 1.335 + /* TODO: Is this needed? */ 1.336 + unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits); 1.337 + unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits); 1.338 + 1.339 + if (info->fShowSign) { 1.340 + /* Reset back to original value regardless of what the error was */ 1.341 + UErrorCode localStatus = U_ZERO_ERROR; 1.342 + u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus); 1.343 + } 1.344 + 1.345 + return handler->pad_and_justify(context, info, result, resultLen); 1.346 +} 1.347 + 1.348 +/* HSYS */ 1.349 +static int32_t 1.350 +u_printf_integer_handler(const u_printf_stream_handler *handler, 1.351 + void *context, 1.352 + ULocaleBundle *formatBundle, 1.353 + const u_printf_spec_info *info, 1.354 + const ufmt_args *args) 1.355 +{ 1.356 + int64_t num = args[0].int64Value; 1.357 + UNumberFormat *format; 1.358 + UChar result[UPRINTF_BUFFER_SIZE]; 1.359 + UChar prefixBuffer[UPRINTF_BUFFER_SIZE]; 1.360 + int32_t prefixBufferLen = sizeof(prefixBuffer); 1.361 + int32_t minDigits = -1; 1.362 + int32_t resultLen; 1.363 + UErrorCode status = U_ZERO_ERROR; 1.364 + 1.365 + prefixBuffer[0] = 0; 1.366 + 1.367 + /* mask off any necessary bits */ 1.368 + if (info->fIsShort) 1.369 + num = (int16_t)num; 1.370 + else if (!info->fIsLongLong) 1.371 + num = (int32_t)num; 1.372 + 1.373 + /* get the formatter */ 1.374 + format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL); 1.375 + 1.376 + /* handle error */ 1.377 + if(format == 0) 1.378 + return 0; 1.379 + 1.380 + /* set the appropriate flags on the formatter */ 1.381 + 1.382 + /* set the minimum integer digits */ 1.383 + if(info->fPrecision != -1) { 1.384 + /* set the minimum # of digits */ 1.385 + minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS); 1.386 + unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision); 1.387 + } 1.388 + 1.389 + /* set whether to show the sign */ 1.390 + if(info->fShowSign) { 1.391 + u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status); 1.392 + } 1.393 + 1.394 + /* format the number */ 1.395 + resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status); 1.396 + 1.397 + if (U_FAILURE(status)) { 1.398 + resultLen = 0; 1.399 + } 1.400 + 1.401 + /* restore the number format */ 1.402 + if (minDigits != -1) { 1.403 + unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits); 1.404 + } 1.405 + 1.406 + if (info->fShowSign) { 1.407 + /* Reset back to original value regardless of what the error was */ 1.408 + UErrorCode localStatus = U_ZERO_ERROR; 1.409 + u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus); 1.410 + } 1.411 + 1.412 + return handler->pad_and_justify(context, info, result, resultLen); 1.413 +} 1.414 + 1.415 +static int32_t 1.416 +u_printf_hex_handler(const u_printf_stream_handler *handler, 1.417 + void *context, 1.418 + ULocaleBundle *formatBundle, 1.419 + const u_printf_spec_info *info, 1.420 + const ufmt_args *args) 1.421 +{ 1.422 + int64_t num = args[0].int64Value; 1.423 + UChar result[UPRINTF_BUFFER_SIZE]; 1.424 + int32_t len = UPRINTF_BUFFER_SIZE; 1.425 + 1.426 + 1.427 + /* mask off any necessary bits */ 1.428 + if (info->fIsShort) 1.429 + num &= UINT16_MAX; 1.430 + else if (!info->fIsLongLong) 1.431 + num &= UINT32_MAX; 1.432 + 1.433 + /* format the number, preserving the minimum # of digits */ 1.434 + ufmt_64tou(result, &len, num, 16, 1.435 + (UBool)(info->fSpec == 0x0078), 1.436 + (info->fPrecision == -1 && info->fZero) ? info->fWidth : info->fPrecision); 1.437 + 1.438 + /* convert to alt form, if desired */ 1.439 + if(num != 0 && info->fAlt && len < UPRINTF_BUFFER_SIZE - 2) { 1.440 + /* shift the formatted string right by 2 chars */ 1.441 + memmove(result + 2, result, len * sizeof(UChar)); 1.442 + result[0] = 0x0030; 1.443 + result[1] = info->fSpec; 1.444 + len += 2; 1.445 + } 1.446 + 1.447 + return handler->pad_and_justify(context, info, result, len); 1.448 +} 1.449 + 1.450 +static int32_t 1.451 +u_printf_octal_handler(const u_printf_stream_handler *handler, 1.452 + void *context, 1.453 + ULocaleBundle *formatBundle, 1.454 + const u_printf_spec_info *info, 1.455 + const ufmt_args *args) 1.456 +{ 1.457 + int64_t num = args[0].int64Value; 1.458 + UChar result[UPRINTF_BUFFER_SIZE]; 1.459 + int32_t len = UPRINTF_BUFFER_SIZE; 1.460 + 1.461 + 1.462 + /* mask off any necessary bits */ 1.463 + if (info->fIsShort) 1.464 + num &= UINT16_MAX; 1.465 + else if (!info->fIsLongLong) 1.466 + num &= UINT32_MAX; 1.467 + 1.468 + /* format the number, preserving the minimum # of digits */ 1.469 + ufmt_64tou(result, &len, num, 8, 1.470 + FALSE, /* doesn't matter for octal */ 1.471 + info->fPrecision == -1 && info->fZero ? info->fWidth : info->fPrecision); 1.472 + 1.473 + /* convert to alt form, if desired */ 1.474 + if(info->fAlt && result[0] != 0x0030 && len < UPRINTF_BUFFER_SIZE - 1) { 1.475 + /* shift the formatted string right by 1 char */ 1.476 + memmove(result + 1, result, len * sizeof(UChar)); 1.477 + result[0] = 0x0030; 1.478 + len += 1; 1.479 + } 1.480 + 1.481 + return handler->pad_and_justify(context, info, result, len); 1.482 +} 1.483 + 1.484 +static int32_t 1.485 +u_printf_uinteger_handler(const u_printf_stream_handler *handler, 1.486 + void *context, 1.487 + ULocaleBundle *formatBundle, 1.488 + const u_printf_spec_info *info, 1.489 + const ufmt_args *args) 1.490 +{ 1.491 + int64_t num = args[0].int64Value; 1.492 + UNumberFormat *format; 1.493 + UChar result[UPRINTF_BUFFER_SIZE]; 1.494 + int32_t minDigits = -1; 1.495 + int32_t resultLen; 1.496 + UErrorCode status = U_ZERO_ERROR; 1.497 + 1.498 + /* TODO: Fix this once uint64_t can be formatted. */ 1.499 + if (info->fIsShort) 1.500 + num &= UINT16_MAX; 1.501 + else if (!info->fIsLongLong) 1.502 + num &= UINT32_MAX; 1.503 + 1.504 + /* get the formatter */ 1.505 + format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL); 1.506 + 1.507 + /* handle error */ 1.508 + if(format == 0) 1.509 + return 0; 1.510 + 1.511 + /* set the appropriate flags on the formatter */ 1.512 + 1.513 + /* set the minimum integer digits */ 1.514 + if(info->fPrecision != -1) { 1.515 + /* set the minimum # of digits */ 1.516 + minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS); 1.517 + unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision); 1.518 + } 1.519 + 1.520 + /* To mirror other stdio implementations, we ignore the sign argument */ 1.521 + 1.522 + /* format the number */ 1.523 + resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status); 1.524 + 1.525 + if (U_FAILURE(status)) { 1.526 + resultLen = 0; 1.527 + } 1.528 + 1.529 + /* restore the number format */ 1.530 + if (minDigits != -1) { 1.531 + unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits); 1.532 + } 1.533 + 1.534 + return handler->pad_and_justify(context, info, result, resultLen); 1.535 +} 1.536 + 1.537 +static int32_t 1.538 +u_printf_pointer_handler(const u_printf_stream_handler *handler, 1.539 + void *context, 1.540 + ULocaleBundle *formatBundle, 1.541 + const u_printf_spec_info *info, 1.542 + const ufmt_args *args) 1.543 +{ 1.544 + UChar result[UPRINTF_BUFFER_SIZE]; 1.545 + int32_t len = UPRINTF_BUFFER_SIZE; 1.546 + 1.547 + /* format the pointer in hex */ 1.548 + ufmt_ptou(result, &len, args[0].ptrValue, TRUE/*, info->fPrecision*/); 1.549 + 1.550 + return handler->pad_and_justify(context, info, result, len); 1.551 +} 1.552 + 1.553 +static int32_t 1.554 +u_printf_scientific_handler(const u_printf_stream_handler *handler, 1.555 + void *context, 1.556 + ULocaleBundle *formatBundle, 1.557 + const u_printf_spec_info *info, 1.558 + const ufmt_args *args) 1.559 +{ 1.560 + double num = (double) (args[0].doubleValue); 1.561 + UNumberFormat *format; 1.562 + UChar result[UPRINTF_BUFFER_SIZE]; 1.563 + UChar prefixBuffer[UPRINTF_BUFFER_SIZE]; 1.564 + int32_t prefixBufferLen = sizeof(prefixBuffer); 1.565 + int32_t minDecimalDigits; 1.566 + int32_t maxDecimalDigits; 1.567 + UErrorCode status = U_ZERO_ERROR; 1.568 + UChar srcExpBuf[UPRINTF_SYMBOL_BUFFER_SIZE]; 1.569 + int32_t srcLen, expLen; 1.570 + int32_t resultLen; 1.571 + UChar expBuf[UPRINTF_SYMBOL_BUFFER_SIZE]; 1.572 + 1.573 + prefixBuffer[0] = 0; 1.574 + 1.575 + /* mask off any necessary bits */ 1.576 + /* if(! info->fIsLongDouble) 1.577 + num &= DBL_MAX;*/ 1.578 + 1.579 + /* get the formatter */ 1.580 + format = u_locbund_getNumberFormat(formatBundle, UNUM_SCIENTIFIC); 1.581 + 1.582 + /* handle error */ 1.583 + if(format == 0) 1.584 + return 0; 1.585 + 1.586 + /* set the appropriate flags on the formatter */ 1.587 + 1.588 + srcLen = unum_getSymbol(format, 1.589 + UNUM_EXPONENTIAL_SYMBOL, 1.590 + srcExpBuf, 1.591 + sizeof(srcExpBuf), 1.592 + &status); 1.593 + 1.594 + /* Upper/lower case the e */ 1.595 + if (info->fSpec == (UChar)0x65 /* e */) { 1.596 + expLen = u_strToLower(expBuf, (int32_t)sizeof(expBuf), 1.597 + srcExpBuf, srcLen, 1.598 + formatBundle->fLocale, 1.599 + &status); 1.600 + } 1.601 + else { 1.602 + expLen = u_strToUpper(expBuf, (int32_t)sizeof(expBuf), 1.603 + srcExpBuf, srcLen, 1.604 + formatBundle->fLocale, 1.605 + &status); 1.606 + } 1.607 + 1.608 + unum_setSymbol(format, 1.609 + UNUM_EXPONENTIAL_SYMBOL, 1.610 + expBuf, 1.611 + expLen, 1.612 + &status); 1.613 + 1.614 + /* save the formatter's state */ 1.615 + minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS); 1.616 + maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS); 1.617 + 1.618 + /* set the appropriate flags and number of decimal digits on the formatter */ 1.619 + if(info->fPrecision != -1) { 1.620 + /* set the # of decimal digits */ 1.621 + if (info->fOrigSpec == (UChar)0x65 /* e */ || info->fOrigSpec == (UChar)0x45 /* E */) { 1.622 + unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision); 1.623 + } 1.624 + else { 1.625 + unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, 1); 1.626 + unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, info->fPrecision); 1.627 + } 1.628 + } 1.629 + else if(info->fAlt) { 1.630 + /* '#' means always show decimal point */ 1.631 + /* copy of printf behavior on Solaris - '#' shows 6 digits */ 1.632 + unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); 1.633 + } 1.634 + else { 1.635 + /* # of decimal digits is 6 if precision not specified */ 1.636 + unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); 1.637 + } 1.638 + 1.639 + /* set whether to show the sign */ 1.640 + if (info->fShowSign) { 1.641 + u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status); 1.642 + } 1.643 + 1.644 + /* format the number */ 1.645 + resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status); 1.646 + 1.647 + if (U_FAILURE(status)) { 1.648 + resultLen = 0; 1.649 + } 1.650 + 1.651 + /* restore the number format */ 1.652 + /* TODO: Is this needed? */ 1.653 + unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits); 1.654 + unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits); 1.655 + 1.656 + /* Since we're the only one using the scientific 1.657 + format, we don't need to save the old exponent value. */ 1.658 + /*unum_setSymbol(format, 1.659 + UNUM_EXPONENTIAL_SYMBOL, 1.660 + srcExpBuf, 1.661 + srcLen, 1.662 + &status);*/ 1.663 + 1.664 + if (info->fShowSign) { 1.665 + /* Reset back to original value regardless of what the error was */ 1.666 + UErrorCode localStatus = U_ZERO_ERROR; 1.667 + u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus); 1.668 + } 1.669 + 1.670 + return handler->pad_and_justify(context, info, result, resultLen); 1.671 +} 1.672 + 1.673 +static int32_t 1.674 +u_printf_percent_handler(const u_printf_stream_handler *handler, 1.675 + void *context, 1.676 + ULocaleBundle *formatBundle, 1.677 + const u_printf_spec_info *info, 1.678 + const ufmt_args *args) 1.679 +{ 1.680 + double num = (double) (args[0].doubleValue); 1.681 + UNumberFormat *format; 1.682 + UChar result[UPRINTF_BUFFER_SIZE]; 1.683 + UChar prefixBuffer[UPRINTF_BUFFER_SIZE]; 1.684 + int32_t prefixBufferLen = sizeof(prefixBuffer); 1.685 + int32_t minDecimalDigits; 1.686 + int32_t maxDecimalDigits; 1.687 + int32_t resultLen; 1.688 + UErrorCode status = U_ZERO_ERROR; 1.689 + 1.690 + prefixBuffer[0] = 0; 1.691 + 1.692 + /* mask off any necessary bits */ 1.693 + /* if(! info->fIsLongDouble) 1.694 + num &= DBL_MAX;*/ 1.695 + 1.696 + /* get the formatter */ 1.697 + format = u_locbund_getNumberFormat(formatBundle, UNUM_PERCENT); 1.698 + 1.699 + /* handle error */ 1.700 + if(format == 0) 1.701 + return 0; 1.702 + 1.703 + /* save the formatter's state */ 1.704 + minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS); 1.705 + maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS); 1.706 + 1.707 + /* set the appropriate flags and number of decimal digits on the formatter */ 1.708 + if(info->fPrecision != -1) { 1.709 + /* set the # of decimal digits */ 1.710 + unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision); 1.711 + } 1.712 + else if(info->fAlt) { 1.713 + /* '#' means always show decimal point */ 1.714 + /* copy of printf behavior on Solaris - '#' shows 6 digits */ 1.715 + unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); 1.716 + } 1.717 + else { 1.718 + /* # of decimal digits is 6 if precision not specified */ 1.719 + unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); 1.720 + } 1.721 + 1.722 + /* set whether to show the sign */ 1.723 + if (info->fShowSign) { 1.724 + u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status); 1.725 + } 1.726 + 1.727 + /* format the number */ 1.728 + resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status); 1.729 + 1.730 + if (U_FAILURE(status)) { 1.731 + resultLen = 0; 1.732 + } 1.733 + 1.734 + /* restore the number format */ 1.735 + /* TODO: Is this needed? */ 1.736 + unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits); 1.737 + unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits); 1.738 + 1.739 + if (info->fShowSign) { 1.740 + /* Reset back to original value regardless of what the error was */ 1.741 + UErrorCode localStatus = U_ZERO_ERROR; 1.742 + u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus); 1.743 + } 1.744 + 1.745 + return handler->pad_and_justify(context, info, result, resultLen); 1.746 +} 1.747 + 1.748 +static int32_t 1.749 +u_printf_ustring_handler(const u_printf_stream_handler *handler, 1.750 + void *context, 1.751 + ULocaleBundle *formatBundle, 1.752 + const u_printf_spec_info *info, 1.753 + const ufmt_args *args) 1.754 +{ 1.755 + int32_t len, written; 1.756 + const UChar *arg = (const UChar*)(args[0].ptrValue); 1.757 + 1.758 + /* allocate enough space for the buffer */ 1.759 + if (arg == NULL) { 1.760 + arg = gNullStr; 1.761 + } 1.762 + len = u_strlen(arg); 1.763 + 1.764 + /* width = minimum # of characters to write */ 1.765 + /* precision = maximum # of characters to write */ 1.766 + if (info->fPrecision != -1 && info->fPrecision < len) { 1.767 + len = info->fPrecision; 1.768 + } 1.769 + 1.770 + /* determine if the string should be padded */ 1.771 + written = handler->pad_and_justify(context, info, arg, len); 1.772 + 1.773 + return written; 1.774 +} 1.775 + 1.776 +static int32_t 1.777 +u_printf_uchar_handler(const u_printf_stream_handler *handler, 1.778 + void *context, 1.779 + ULocaleBundle *formatBundle, 1.780 + const u_printf_spec_info *info, 1.781 + const ufmt_args *args) 1.782 +{ 1.783 + int32_t written = 0; 1.784 + UChar arg = (UChar)(args[0].int64Value); 1.785 + 1.786 + /* width = minimum # of characters to write */ 1.787 + /* precision = maximum # of characters to write */ 1.788 + /* precision is ignored when handling a uchar */ 1.789 + 1.790 + /* determine if the string should be padded */ 1.791 + written = handler->pad_and_justify(context, info, &arg, 1); 1.792 + 1.793 + return written; 1.794 +} 1.795 + 1.796 +static int32_t 1.797 +u_printf_scidbl_handler(const u_printf_stream_handler *handler, 1.798 + void *context, 1.799 + ULocaleBundle *formatBundle, 1.800 + const u_printf_spec_info *info, 1.801 + const ufmt_args *args) 1.802 +{ 1.803 + u_printf_spec_info scidbl_info; 1.804 + double num = args[0].doubleValue; 1.805 + int32_t retVal; 1.806 + UNumberFormat *format; 1.807 + int32_t maxSigDecimalDigits, significantDigits; 1.808 + 1.809 + memcpy(&scidbl_info, info, sizeof(u_printf_spec_info)); 1.810 + 1.811 + /* determine whether to use 'd', 'e' or 'f' notation */ 1.812 + if (scidbl_info.fPrecision == -1 && num == uprv_trunc(num)) 1.813 + { 1.814 + /* use 'f' notation */ 1.815 + scidbl_info.fSpec = 0x0066; 1.816 + scidbl_info.fPrecision = 0; 1.817 + /* call the double handler */ 1.818 + retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args); 1.819 + } 1.820 + else if(num < 0.0001 || (scidbl_info.fPrecision < 1 && 1000000.0 <= num) 1.821 + || (scidbl_info.fPrecision != -1 && num > uprv_pow10(scidbl_info.fPrecision))) 1.822 + { 1.823 + /* use 'e' or 'E' notation */ 1.824 + scidbl_info.fSpec = scidbl_info.fSpec - 2; 1.825 + if (scidbl_info.fPrecision == -1) { 1.826 + scidbl_info.fPrecision = 5; 1.827 + } 1.828 + /* call the scientific handler */ 1.829 + retVal = u_printf_scientific_handler(handler, context, formatBundle, &scidbl_info, args); 1.830 + } 1.831 + else { 1.832 + format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL); 1.833 + /* Check for null pointer */ 1.834 + if (format == NULL) { 1.835 + return 0; 1.836 + } 1.837 + maxSigDecimalDigits = unum_getAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS); 1.838 + significantDigits = scidbl_info.fPrecision; 1.839 + 1.840 + /* use 'f' notation */ 1.841 + scidbl_info.fSpec = 0x0066; 1.842 + if (significantDigits == -1) { 1.843 + significantDigits = 6; 1.844 + } 1.845 + unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, TRUE); 1.846 + unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, significantDigits); 1.847 + /* call the double handler */ 1.848 + retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args); 1.849 + unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, maxSigDecimalDigits); 1.850 + unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, FALSE); 1.851 + } 1.852 + return retVal; 1.853 +} 1.854 + 1.855 +static int32_t 1.856 +u_printf_count_handler(const u_printf_stream_handler *handler, 1.857 + void *context, 1.858 + ULocaleBundle *formatBundle, 1.859 + const u_printf_spec_info *info, 1.860 + const ufmt_args *args) 1.861 +{ 1.862 + int32_t *count = (int32_t*)(args[0].ptrValue); 1.863 + 1.864 + /* in the special case of count, the u_printf_spec_info's width */ 1.865 + /* will contain the # of chars written thus far */ 1.866 + *count = info->fWidth; 1.867 + 1.868 + return 0; 1.869 +} 1.870 + 1.871 +static int32_t 1.872 +u_printf_spellout_handler(const u_printf_stream_handler *handler, 1.873 + void *context, 1.874 + ULocaleBundle *formatBundle, 1.875 + const u_printf_spec_info *info, 1.876 + const ufmt_args *args) 1.877 +{ 1.878 + double num = (double) (args[0].doubleValue); 1.879 + UNumberFormat *format; 1.880 + UChar result[UPRINTF_BUFFER_SIZE]; 1.881 + UChar prefixBuffer[UPRINTF_BUFFER_SIZE]; 1.882 + int32_t prefixBufferLen = sizeof(prefixBuffer); 1.883 + int32_t minDecimalDigits; 1.884 + int32_t maxDecimalDigits; 1.885 + int32_t resultLen; 1.886 + UErrorCode status = U_ZERO_ERROR; 1.887 + 1.888 + prefixBuffer[0] = 0; 1.889 + 1.890 + /* mask off any necessary bits */ 1.891 + /* if(! info->fIsLongDouble) 1.892 + num &= DBL_MAX;*/ 1.893 + 1.894 + /* get the formatter */ 1.895 + format = u_locbund_getNumberFormat(formatBundle, UNUM_SPELLOUT); 1.896 + 1.897 + /* handle error */ 1.898 + if(format == 0) 1.899 + return 0; 1.900 + 1.901 + /* save the formatter's state */ 1.902 + minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS); 1.903 + maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS); 1.904 + 1.905 + /* set the appropriate flags and number of decimal digits on the formatter */ 1.906 + if(info->fPrecision != -1) { 1.907 + /* set the # of decimal digits */ 1.908 + unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision); 1.909 + } 1.910 + else if(info->fAlt) { 1.911 + /* '#' means always show decimal point */ 1.912 + /* copy of printf behavior on Solaris - '#' shows 6 digits */ 1.913 + unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); 1.914 + } 1.915 + else { 1.916 + /* # of decimal digits is 6 if precision not specified */ 1.917 + unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); 1.918 + } 1.919 + 1.920 + /* set whether to show the sign */ 1.921 + if (info->fShowSign) { 1.922 + u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status); 1.923 + } 1.924 + 1.925 + /* format the number */ 1.926 + resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status); 1.927 + 1.928 + if (U_FAILURE(status)) { 1.929 + resultLen = 0; 1.930 + } 1.931 + 1.932 + /* restore the number format */ 1.933 + /* TODO: Is this needed? */ 1.934 + unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits); 1.935 + unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits); 1.936 + 1.937 + if (info->fShowSign) { 1.938 + /* Reset back to original value regardless of what the error was */ 1.939 + UErrorCode localStatus = U_ZERO_ERROR; 1.940 + u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus); 1.941 + } 1.942 + 1.943 + return handler->pad_and_justify(context, info, result, resultLen); 1.944 +} 1.945 + 1.946 +/* Use US-ASCII characters only for formatting. Most codepages have 1.947 + characters 20-7F from Unicode. Using any other codepage specific 1.948 + characters will make it very difficult to format the string on 1.949 + non-Unicode machines */ 1.950 +static const u_printf_info g_u_printf_infos[UPRINTF_NUM_FMT_HANDLERS] = { 1.951 +/* 0x20 */ 1.952 + UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 1.953 + UFMT_EMPTY, UFMT_SIMPLE_PERCENT,UFMT_EMPTY, UFMT_EMPTY, 1.954 + UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 1.955 + UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 1.956 + 1.957 +/* 0x30 */ 1.958 + UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 1.959 + UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 1.960 + UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 1.961 + UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 1.962 + 1.963 +/* 0x40 */ 1.964 + UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_UCHAR, 1.965 + UFMT_EMPTY, UFMT_SCIENTIFIC, UFMT_EMPTY, UFMT_SCIDBL, 1.966 +#ifdef U_USE_OBSOLETE_IO_FORMATTING 1.967 + UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_UCHAR/*deprecated*/, 1.968 +#else 1.969 + UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 1.970 +#endif 1.971 + UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 1.972 + 1.973 +/* 0x50 */ 1.974 + UFMT_PERCENT, UFMT_EMPTY, UFMT_EMPTY, UFMT_USTRING, 1.975 +#ifdef U_USE_OBSOLETE_IO_FORMATTING 1.976 + UFMT_EMPTY, UFMT_USTRING/*deprecated*/,UFMT_SPELLOUT, UFMT_EMPTY, 1.977 +#else 1.978 + UFMT_EMPTY, UFMT_EMPTY, UFMT_SPELLOUT, UFMT_EMPTY, 1.979 +#endif 1.980 + UFMT_HEX, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 1.981 + UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 1.982 + 1.983 +/* 0x60 */ 1.984 + UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_CHAR, 1.985 + UFMT_INT, UFMT_SCIENTIFIC, UFMT_DOUBLE, UFMT_SCIDBL, 1.986 + UFMT_EMPTY, UFMT_INT, UFMT_EMPTY, UFMT_EMPTY, 1.987 + UFMT_EMPTY, UFMT_EMPTY, UFMT_COUNT, UFMT_OCTAL, 1.988 + 1.989 +/* 0x70 */ 1.990 + UFMT_POINTER, UFMT_EMPTY, UFMT_EMPTY, UFMT_STRING, 1.991 + UFMT_EMPTY, UFMT_UINT, UFMT_EMPTY, UFMT_EMPTY, 1.992 + UFMT_HEX, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 1.993 + UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 1.994 +}; 1.995 + 1.996 +/* flag characters for uprintf */ 1.997 +#define FLAG_MINUS 0x002D 1.998 +#define FLAG_PLUS 0x002B 1.999 +#define FLAG_SPACE 0x0020 1.1000 +#define FLAG_POUND 0x0023 1.1001 +#define FLAG_ZERO 0x0030 1.1002 +#define FLAG_PAREN 0x0028 1.1003 + 1.1004 +#define ISFLAG(s) (s) == FLAG_MINUS || \ 1.1005 + (s) == FLAG_PLUS || \ 1.1006 + (s) == FLAG_SPACE || \ 1.1007 + (s) == FLAG_POUND || \ 1.1008 + (s) == FLAG_ZERO || \ 1.1009 + (s) == FLAG_PAREN 1.1010 + 1.1011 +/* special characters for uprintf */ 1.1012 +#define SPEC_ASTERISK 0x002A 1.1013 +#define SPEC_DOLLARSIGN 0x0024 1.1014 +#define SPEC_PERIOD 0x002E 1.1015 +#define SPEC_PERCENT 0x0025 1.1016 + 1.1017 +/* unicode digits */ 1.1018 +#define DIGIT_ZERO 0x0030 1.1019 +#define DIGIT_ONE 0x0031 1.1020 +#define DIGIT_TWO 0x0032 1.1021 +#define DIGIT_THREE 0x0033 1.1022 +#define DIGIT_FOUR 0x0034 1.1023 +#define DIGIT_FIVE 0x0035 1.1024 +#define DIGIT_SIX 0x0036 1.1025 +#define DIGIT_SEVEN 0x0037 1.1026 +#define DIGIT_EIGHT 0x0038 1.1027 +#define DIGIT_NINE 0x0039 1.1028 + 1.1029 +#define ISDIGIT(s) (s) == DIGIT_ZERO || \ 1.1030 + (s) == DIGIT_ONE || \ 1.1031 + (s) == DIGIT_TWO || \ 1.1032 + (s) == DIGIT_THREE || \ 1.1033 + (s) == DIGIT_FOUR || \ 1.1034 + (s) == DIGIT_FIVE || \ 1.1035 + (s) == DIGIT_SIX || \ 1.1036 + (s) == DIGIT_SEVEN || \ 1.1037 + (s) == DIGIT_EIGHT || \ 1.1038 + (s) == DIGIT_NINE 1.1039 + 1.1040 +/* u_printf modifiers */ 1.1041 +#define MOD_H 0x0068 1.1042 +#define MOD_LOWERL 0x006C 1.1043 +#define MOD_L 0x004C 1.1044 + 1.1045 +#define ISMOD(s) (s) == MOD_H || \ 1.1046 + (s) == MOD_LOWERL || \ 1.1047 + (s) == MOD_L 1.1048 +/* Returns an array of the parsed argument type given in the format string. */ 1.1049 +static ufmt_args* parseArguments(const UChar *alias, va_list ap, UErrorCode *status) { 1.1050 + ufmt_args *arglist = NULL; 1.1051 + ufmt_type_info *typelist = NULL; 1.1052 + UBool *islonglong = NULL; 1.1053 + int32_t size = 0; 1.1054 + int32_t pos = 0; 1.1055 + UChar type; 1.1056 + uint16_t handlerNum; 1.1057 + const UChar *aliasStart = alias; 1.1058 + 1.1059 + /* get maximum number of arguments */ 1.1060 + for(;;) { 1.1061 + /* find % */ 1.1062 + while(*alias != UP_PERCENT && *alias != 0x0000) { 1.1063 + alias++; 1.1064 + } 1.1065 + 1.1066 + if(*alias == 0x0000) { 1.1067 + break; 1.1068 + } 1.1069 + 1.1070 + alias++; 1.1071 + 1.1072 + /* handle the pos number */ 1.1073 + if(ISDIGIT(*alias)) { 1.1074 + 1.1075 + /* handle positional parameters */ 1.1076 + if(ISDIGIT(*alias)) { 1.1077 + pos = (int) (*alias++ - DIGIT_ZERO); 1.1078 + 1.1079 + while(ISDIGIT(*alias)) { 1.1080 + pos *= 10; 1.1081 + pos += (int) (*alias++ - DIGIT_ZERO); 1.1082 + } 1.1083 + } 1.1084 + 1.1085 + /* if there is no '$', don't read anything */ 1.1086 + if(*alias != SPEC_DOLLARSIGN) { 1.1087 + return NULL; 1.1088 + } 1.1089 + } else { 1.1090 + return NULL; 1.1091 + } 1.1092 + 1.1093 + if (pos > size) { 1.1094 + size = pos; 1.1095 + } 1.1096 + } 1.1097 + 1.1098 + /* create the parsed argument list */ 1.1099 + typelist = (ufmt_type_info*)uprv_malloc(sizeof(ufmt_type_info) * size); 1.1100 + islonglong = (UBool*)uprv_malloc(sizeof(UBool) * size); 1.1101 + arglist = (ufmt_args*)uprv_malloc(sizeof(ufmt_args) * size); 1.1102 + 1.1103 + /* If malloc failed, return NULL */ 1.1104 + if (!typelist || !islonglong || !arglist) { 1.1105 + if (typelist) { 1.1106 + uprv_free(typelist); 1.1107 + } 1.1108 + 1.1109 + if (islonglong) { 1.1110 + uprv_free(islonglong); 1.1111 + } 1.1112 + 1.1113 + if (arglist) { 1.1114 + uprv_free(arglist); 1.1115 + } 1.1116 + 1.1117 + *status = U_MEMORY_ALLOCATION_ERROR; 1.1118 + return NULL; 1.1119 + } 1.1120 + 1.1121 + /* reset alias back to the beginning */ 1.1122 + alias = aliasStart; 1.1123 + 1.1124 + for(;;) { 1.1125 + /* find % */ 1.1126 + while(*alias != UP_PERCENT && *alias != 0x0000) { 1.1127 + alias++; 1.1128 + } 1.1129 + 1.1130 + if(*alias == 0x0000) { 1.1131 + break; 1.1132 + } 1.1133 + 1.1134 + alias++; 1.1135 + 1.1136 + /* handle positional parameters */ 1.1137 + if(ISDIGIT(*alias)) { 1.1138 + pos = (int) (*alias++ - DIGIT_ZERO); 1.1139 + 1.1140 + while(ISDIGIT(*alias)) { 1.1141 + pos *= 10; 1.1142 + pos += (int) (*alias++ - DIGIT_ZERO); 1.1143 + } 1.1144 + } 1.1145 + /* offset position by 1 */ 1.1146 + pos--; 1.1147 + 1.1148 + /* skip over everything except for the type */ 1.1149 + while (ISMOD(*alias) || ISFLAG(*alias) || ISDIGIT(*alias) || 1.1150 + *alias == SPEC_ASTERISK || *alias == SPEC_PERIOD || *alias == SPEC_DOLLARSIGN) { 1.1151 + islonglong[pos] = FALSE; 1.1152 + if (ISMOD(*alias)) { 1.1153 + alias++; 1.1154 + if (*alias == MOD_LOWERL) { 1.1155 + islonglong[pos] = TRUE; 1.1156 + } 1.1157 + } 1.1158 + alias++; 1.1159 + } 1.1160 + type = *alias; 1.1161 + 1.1162 + /* store the argument type in the correct position of the parsed argument list */ 1.1163 + handlerNum = (uint16_t)(type - UPRINTF_BASE_FMT_HANDLERS); 1.1164 + if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) { 1.1165 + typelist[pos] = g_u_printf_infos[ handlerNum ].info; 1.1166 + } else { 1.1167 + typelist[pos] = ufmt_empty; 1.1168 + } 1.1169 + } 1.1170 + 1.1171 + /* store argument in arglist */ 1.1172 + for (pos = 0; pos < size; pos++) { 1.1173 + switch (typelist[pos]) { 1.1174 + case ufmt_string: 1.1175 + case ufmt_ustring: 1.1176 + case ufmt_pointer: 1.1177 + arglist[pos].ptrValue = va_arg(ap, void*); 1.1178 + break; 1.1179 + case ufmt_char: 1.1180 + case ufmt_uchar: 1.1181 + case ufmt_int: 1.1182 + if (islonglong[pos]) { 1.1183 + arglist[pos].int64Value = va_arg(ap, int64_t); 1.1184 + } 1.1185 + else { 1.1186 + arglist[pos].int64Value = va_arg(ap, int32_t); 1.1187 + } 1.1188 + break; 1.1189 + case ufmt_float: 1.1190 + arglist[pos].floatValue = (float) va_arg(ap, double); 1.1191 + break; 1.1192 + case ufmt_double: 1.1193 + arglist[pos].doubleValue = va_arg(ap, double); 1.1194 + break; 1.1195 + default: 1.1196 + /* else args is ignored */ 1.1197 + arglist[pos].ptrValue = NULL; 1.1198 + break; 1.1199 + } 1.1200 + } 1.1201 + 1.1202 + uprv_free(typelist); 1.1203 + uprv_free(islonglong); 1.1204 + 1.1205 + return arglist; 1.1206 +} 1.1207 + 1.1208 +/* We parse the argument list in Unicode */ 1.1209 +U_CFUNC int32_t 1.1210 +u_printf_parse(const u_printf_stream_handler *streamHandler, 1.1211 + const UChar *fmt, 1.1212 + void *context, 1.1213 + u_localized_print_string *locStringContext, 1.1214 + ULocaleBundle *formatBundle, 1.1215 + int32_t *written, 1.1216 + va_list ap) 1.1217 +{ 1.1218 + uint16_t handlerNum; 1.1219 + ufmt_args args; 1.1220 + ufmt_type_info argType; 1.1221 + u_printf_handler *handler; 1.1222 + u_printf_spec spec; 1.1223 + u_printf_spec_info *info = &(spec.fInfo); 1.1224 + 1.1225 + const UChar *alias = fmt; 1.1226 + const UChar *backup; 1.1227 + const UChar *lastAlias; 1.1228 + const UChar *orgAlias = fmt; 1.1229 + /* parsed argument list */ 1.1230 + ufmt_args *arglist = NULL; /* initialized it to avoid compiler warnings */ 1.1231 + UErrorCode status = U_ZERO_ERROR; 1.1232 + if (!locStringContext || locStringContext->available >= 0) { 1.1233 + /* get the parsed list of argument types */ 1.1234 + arglist = parseArguments(orgAlias, ap, &status); 1.1235 + 1.1236 + /* Return error if parsing failed. */ 1.1237 + if (U_FAILURE(status)) { 1.1238 + return -1; 1.1239 + } 1.1240 + } 1.1241 + 1.1242 + /* iterate through the pattern */ 1.1243 + while(!locStringContext || locStringContext->available >= 0) { 1.1244 + 1.1245 + /* find the next '%' */ 1.1246 + lastAlias = alias; 1.1247 + while(*alias != UP_PERCENT && *alias != 0x0000) { 1.1248 + alias++; 1.1249 + } 1.1250 + 1.1251 + /* write any characters before the '%' */ 1.1252 + if(alias > lastAlias) { 1.1253 + *written += (streamHandler->write)(context, lastAlias, (int32_t)(alias - lastAlias)); 1.1254 + } 1.1255 + 1.1256 + /* break if at end of string */ 1.1257 + if(*alias == 0x0000) { 1.1258 + break; 1.1259 + } 1.1260 + 1.1261 + /* initialize spec to default values */ 1.1262 + spec.fWidthPos = -1; 1.1263 + spec.fPrecisionPos = -1; 1.1264 + spec.fArgPos = -1; 1.1265 + 1.1266 + uprv_memset(info, 0, sizeof(*info)); 1.1267 + info->fPrecision = -1; 1.1268 + info->fWidth = -1; 1.1269 + info->fPadChar = 0x0020; 1.1270 + 1.1271 + /* skip over the initial '%' */ 1.1272 + alias++; 1.1273 + 1.1274 + /* Check for positional argument */ 1.1275 + if(ISDIGIT(*alias)) { 1.1276 + 1.1277 + /* Save the current position */ 1.1278 + backup = alias; 1.1279 + 1.1280 + /* handle positional parameters */ 1.1281 + if(ISDIGIT(*alias)) { 1.1282 + spec.fArgPos = (int) (*alias++ - DIGIT_ZERO); 1.1283 + 1.1284 + while(ISDIGIT(*alias)) { 1.1285 + spec.fArgPos *= 10; 1.1286 + spec.fArgPos += (int) (*alias++ - DIGIT_ZERO); 1.1287 + } 1.1288 + } 1.1289 + 1.1290 + /* if there is no '$', don't read anything */ 1.1291 + if(*alias != SPEC_DOLLARSIGN) { 1.1292 + spec.fArgPos = -1; 1.1293 + alias = backup; 1.1294 + } 1.1295 + /* munge the '$' */ 1.1296 + else 1.1297 + alias++; 1.1298 + } 1.1299 + 1.1300 + /* Get any format flags */ 1.1301 + while(ISFLAG(*alias)) { 1.1302 + switch(*alias++) { 1.1303 + 1.1304 + /* left justify */ 1.1305 + case FLAG_MINUS: 1.1306 + info->fLeft = TRUE; 1.1307 + break; 1.1308 + 1.1309 + /* always show sign */ 1.1310 + case FLAG_PLUS: 1.1311 + info->fShowSign = TRUE; 1.1312 + break; 1.1313 + 1.1314 + /* use space if no sign present */ 1.1315 + case FLAG_SPACE: 1.1316 + info->fShowSign = TRUE; 1.1317 + info->fSpace = TRUE; 1.1318 + break; 1.1319 + 1.1320 + /* use alternate form */ 1.1321 + case FLAG_POUND: 1.1322 + info->fAlt = TRUE; 1.1323 + break; 1.1324 + 1.1325 + /* pad with leading zeroes */ 1.1326 + case FLAG_ZERO: 1.1327 + info->fZero = TRUE; 1.1328 + info->fPadChar = 0x0030; 1.1329 + break; 1.1330 + 1.1331 + /* pad character specified */ 1.1332 + case FLAG_PAREN: 1.1333 + 1.1334 + /* TODO test that all four are numbers */ 1.1335 + /* first four characters are hex values for pad char */ 1.1336 + info->fPadChar = (UChar)ufmt_digitvalue(*alias++); 1.1337 + info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++)); 1.1338 + info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++)); 1.1339 + info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++)); 1.1340 + 1.1341 + /* final character is ignored */ 1.1342 + alias++; 1.1343 + 1.1344 + break; 1.1345 + } 1.1346 + } 1.1347 + 1.1348 + /* Get the width */ 1.1349 + 1.1350 + /* width is specified out of line */ 1.1351 + if(*alias == SPEC_ASTERISK) { 1.1352 + 1.1353 + info->fWidth = -2; 1.1354 + 1.1355 + /* Skip the '*' */ 1.1356 + alias++; 1.1357 + 1.1358 + /* Save the current position */ 1.1359 + backup = alias; 1.1360 + 1.1361 + /* handle positional parameters */ 1.1362 + if(ISDIGIT(*alias)) { 1.1363 + spec.fWidthPos = (int) (*alias++ - DIGIT_ZERO); 1.1364 + 1.1365 + while(ISDIGIT(*alias)) { 1.1366 + spec.fWidthPos *= 10; 1.1367 + spec.fWidthPos += (int) (*alias++ - DIGIT_ZERO); 1.1368 + } 1.1369 + } 1.1370 + 1.1371 + /* if there is no '$', don't read anything */ 1.1372 + if(*alias != SPEC_DOLLARSIGN) { 1.1373 + spec.fWidthPos = -1; 1.1374 + alias = backup; 1.1375 + } 1.1376 + /* munge the '$' */ 1.1377 + else 1.1378 + alias++; 1.1379 + } 1.1380 + /* read the width, if present */ 1.1381 + else if(ISDIGIT(*alias)){ 1.1382 + info->fWidth = (int) (*alias++ - DIGIT_ZERO); 1.1383 + 1.1384 + while(ISDIGIT(*alias)) { 1.1385 + info->fWidth *= 10; 1.1386 + info->fWidth += (int) (*alias++ - DIGIT_ZERO); 1.1387 + } 1.1388 + } 1.1389 + 1.1390 + /* Get the precision */ 1.1391 + 1.1392 + if(*alias == SPEC_PERIOD) { 1.1393 + 1.1394 + /* eat up the '.' */ 1.1395 + alias++; 1.1396 + 1.1397 + /* precision is specified out of line */ 1.1398 + if(*alias == SPEC_ASTERISK) { 1.1399 + 1.1400 + info->fPrecision = -2; 1.1401 + 1.1402 + /* Skip the '*' */ 1.1403 + alias++; 1.1404 + 1.1405 + /* save the current position */ 1.1406 + backup = alias; 1.1407 + 1.1408 + /* handle positional parameters */ 1.1409 + if(ISDIGIT(*alias)) { 1.1410 + spec.fPrecisionPos = (int) (*alias++ - DIGIT_ZERO); 1.1411 + 1.1412 + while(ISDIGIT(*alias)) { 1.1413 + spec.fPrecisionPos *= 10; 1.1414 + spec.fPrecisionPos += (int) (*alias++ - DIGIT_ZERO); 1.1415 + } 1.1416 + 1.1417 + /* if there is no '$', don't read anything */ 1.1418 + if(*alias != SPEC_DOLLARSIGN) { 1.1419 + spec.fPrecisionPos = -1; 1.1420 + alias = backup; 1.1421 + } 1.1422 + else { 1.1423 + /* munge the '$' */ 1.1424 + alias++; 1.1425 + } 1.1426 + } 1.1427 + } 1.1428 + /* read the precision */ 1.1429 + else if(ISDIGIT(*alias)){ 1.1430 + info->fPrecision = (int) (*alias++ - DIGIT_ZERO); 1.1431 + 1.1432 + while(ISDIGIT(*alias)) { 1.1433 + info->fPrecision *= 10; 1.1434 + info->fPrecision += (int) (*alias++ - DIGIT_ZERO); 1.1435 + } 1.1436 + } 1.1437 + } 1.1438 + 1.1439 + /* Get any modifiers */ 1.1440 + if(ISMOD(*alias)) { 1.1441 + switch(*alias++) { 1.1442 + 1.1443 + /* short */ 1.1444 + case MOD_H: 1.1445 + info->fIsShort = TRUE; 1.1446 + break; 1.1447 + 1.1448 + /* long or long long */ 1.1449 + case MOD_LOWERL: 1.1450 + if(*alias == MOD_LOWERL) { 1.1451 + info->fIsLongLong = TRUE; 1.1452 + /* skip over the next 'l' */ 1.1453 + alias++; 1.1454 + } 1.1455 + else 1.1456 + info->fIsLong = TRUE; 1.1457 + break; 1.1458 + 1.1459 + /* long double */ 1.1460 + case MOD_L: 1.1461 + info->fIsLongDouble = TRUE; 1.1462 + break; 1.1463 + } 1.1464 + } 1.1465 + 1.1466 + /* finally, get the specifier letter */ 1.1467 + info->fSpec = *alias++; 1.1468 + info->fOrigSpec = info->fSpec; 1.1469 + 1.1470 + /* fill in the precision and width, if specified out of line */ 1.1471 + 1.1472 + /* width specified out of line */ 1.1473 + if(spec.fInfo.fWidth == -2) { 1.1474 + if(spec.fWidthPos == -1) { 1.1475 + /* read the width from the argument list */ 1.1476 + info->fWidth = va_arg(ap, int32_t); 1.1477 + } 1.1478 + /* else handle positional parameter */ 1.1479 + 1.1480 + /* if it's negative, take the absolute value and set left alignment */ 1.1481 + if(info->fWidth < 0) { 1.1482 + info->fWidth *= -1; /* Make positive */ 1.1483 + info->fLeft = TRUE; 1.1484 + } 1.1485 + } 1.1486 + 1.1487 + /* precision specified out of line */ 1.1488 + if(info->fPrecision == -2) { 1.1489 + if(spec.fPrecisionPos == -1) { 1.1490 + /* read the precision from the argument list */ 1.1491 + info->fPrecision = va_arg(ap, int32_t); 1.1492 + } 1.1493 + /* else handle positional parameter */ 1.1494 + 1.1495 + /* if it's negative, set it to zero */ 1.1496 + if(info->fPrecision < 0) 1.1497 + info->fPrecision = 0; 1.1498 + } 1.1499 + 1.1500 + handlerNum = (uint16_t)(info->fSpec - UPRINTF_BASE_FMT_HANDLERS); 1.1501 + if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) { 1.1502 + /* query the info function for argument information */ 1.1503 + argType = g_u_printf_infos[ handlerNum ].info; 1.1504 + 1.1505 + /* goto the correct argument on arg_list if position is specified */ 1.1506 + if (spec.fArgPos > 0) { 1.1507 + /* offset position by 1 */ 1.1508 + spec.fArgPos--; 1.1509 + switch(argType) { 1.1510 + case ufmt_count: 1.1511 + /* set the spec's width to the # of chars written */ 1.1512 + info->fWidth = *written; 1.1513 + /* fall through to set the pointer */ 1.1514 + case ufmt_string: 1.1515 + case ufmt_ustring: 1.1516 + case ufmt_pointer: 1.1517 + args.ptrValue = arglist[spec.fArgPos].ptrValue; 1.1518 + break; 1.1519 + case ufmt_char: 1.1520 + case ufmt_uchar: 1.1521 + case ufmt_int: 1.1522 + args.int64Value = arglist[spec.fArgPos].int64Value; 1.1523 + break; 1.1524 + case ufmt_float: 1.1525 + args.floatValue = arglist[spec.fArgPos].floatValue; 1.1526 + break; 1.1527 + case ufmt_double: 1.1528 + args.doubleValue = arglist[spec.fArgPos].doubleValue; 1.1529 + break; 1.1530 + default: 1.1531 + /* else args is ignored */ 1.1532 + args.ptrValue = NULL; 1.1533 + break; 1.1534 + } 1.1535 + } else { /* no positional argument specified */ 1.1536 + switch(argType) { 1.1537 + case ufmt_count: 1.1538 + /* set the spec's width to the # of chars written */ 1.1539 + info->fWidth = *written; 1.1540 + /* fall through to set the pointer */ 1.1541 + case ufmt_string: 1.1542 + case ufmt_ustring: 1.1543 + case ufmt_pointer: 1.1544 + args.ptrValue = va_arg(ap, void*); 1.1545 + break; 1.1546 + case ufmt_char: 1.1547 + case ufmt_uchar: 1.1548 + case ufmt_int: 1.1549 + if (info->fIsLongLong) { 1.1550 + args.int64Value = va_arg(ap, int64_t); 1.1551 + } 1.1552 + else { 1.1553 + args.int64Value = va_arg(ap, int32_t); 1.1554 + } 1.1555 + break; 1.1556 + case ufmt_float: 1.1557 + args.floatValue = (float) va_arg(ap, double); 1.1558 + break; 1.1559 + case ufmt_double: 1.1560 + args.doubleValue = va_arg(ap, double); 1.1561 + break; 1.1562 + default: 1.1563 + /* else args is ignored */ 1.1564 + args.ptrValue = NULL; 1.1565 + break; 1.1566 + } 1.1567 + } 1.1568 + 1.1569 + /* call the handler function */ 1.1570 + handler = g_u_printf_infos[ handlerNum ].handler; 1.1571 + if(handler != 0) { 1.1572 + *written += (*handler)(streamHandler, context, formatBundle, info, &args); 1.1573 + } 1.1574 + else { 1.1575 + /* just echo unknown tags */ 1.1576 + *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias)); 1.1577 + } 1.1578 + } 1.1579 + else { 1.1580 + /* just echo unknown tags */ 1.1581 + *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias)); 1.1582 + } 1.1583 + } 1.1584 + /* delete parsed argument list */ 1.1585 + if (arglist != NULL) { 1.1586 + uprv_free(arglist); 1.1587 + } 1.1588 + /* return # of characters in this format that have been parsed. */ 1.1589 + return (int32_t)(alias - fmt); 1.1590 +} 1.1591 + 1.1592 +#endif /* #if !UCONFIG_NO_FORMATTING */