intl/icu/source/io/uprntf_p.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /*
michael@0 2 ******************************************************************************
michael@0 3 *
michael@0 4 * Copyright (C) 1998-2011, International Business Machines
michael@0 5 * Corporation and others. All Rights Reserved.
michael@0 6 *
michael@0 7 ******************************************************************************
michael@0 8 *
michael@0 9 * File uprntf_p.c
michael@0 10 *
michael@0 11 * Modification History:
michael@0 12 *
michael@0 13 * Date Name Description
michael@0 14 * 11/23/98 stephen Creation.
michael@0 15 * 03/12/99 stephen Modified for new C API.
michael@0 16 * 08/07/2003 george Reunify printf implementations
michael@0 17 ******************************************************************************
michael@0 18 */
michael@0 19
michael@0 20 #include "unicode/utypes.h"
michael@0 21
michael@0 22 #if !UCONFIG_NO_FORMATTING
michael@0 23
michael@0 24 #include "unicode/ustring.h"
michael@0 25 #include "unicode/utf16.h"
michael@0 26 #include "uprintf.h"
michael@0 27 #include "ufmt_cmn.h"
michael@0 28 #include "cmemory.h"
michael@0 29 #include "putilimp.h"
michael@0 30
michael@0 31 /* ANSI style formatting */
michael@0 32 /* Use US-ASCII characters only for formatting */
michael@0 33
michael@0 34 /* % */
michael@0 35 #define UFMT_SIMPLE_PERCENT {ufmt_simple_percent, u_printf_simple_percent_handler}
michael@0 36 /* s */
michael@0 37 #define UFMT_STRING {ufmt_string, u_printf_string_handler}
michael@0 38 /* c */
michael@0 39 #define UFMT_CHAR {ufmt_char, u_printf_char_handler}
michael@0 40 /* d, i */
michael@0 41 #define UFMT_INT {ufmt_int, u_printf_integer_handler}
michael@0 42 /* u */
michael@0 43 #define UFMT_UINT {ufmt_int, u_printf_uinteger_handler}
michael@0 44 /* o */
michael@0 45 #define UFMT_OCTAL {ufmt_int, u_printf_octal_handler}
michael@0 46 /* x, X */
michael@0 47 #define UFMT_HEX {ufmt_int, u_printf_hex_handler}
michael@0 48 /* f */
michael@0 49 #define UFMT_DOUBLE {ufmt_double, u_printf_double_handler}
michael@0 50 /* e, E */
michael@0 51 #define UFMT_SCIENTIFIC {ufmt_double, u_printf_scientific_handler}
michael@0 52 /* g, G */
michael@0 53 #define UFMT_SCIDBL {ufmt_double, u_printf_scidbl_handler}
michael@0 54 /* n */
michael@0 55 #define UFMT_COUNT {ufmt_count, u_printf_count_handler}
michael@0 56
michael@0 57 /* non-ANSI extensions */
michael@0 58 /* Use US-ASCII characters only for formatting */
michael@0 59
michael@0 60 /* p */
michael@0 61 #define UFMT_POINTER {ufmt_pointer, u_printf_pointer_handler}
michael@0 62 /* V */
michael@0 63 #define UFMT_SPELLOUT {ufmt_double, u_printf_spellout_handler}
michael@0 64 /* P */
michael@0 65 #define UFMT_PERCENT {ufmt_double, u_printf_percent_handler}
michael@0 66 /* C K is old format */
michael@0 67 #define UFMT_UCHAR {ufmt_uchar, u_printf_uchar_handler}
michael@0 68 /* S U is old format */
michael@0 69 #define UFMT_USTRING {ufmt_ustring, u_printf_ustring_handler}
michael@0 70
michael@0 71
michael@0 72 #define UFMT_EMPTY {ufmt_empty, NULL}
michael@0 73
michael@0 74 /**
michael@0 75 * A u_printf handler function.
michael@0 76 * A u_printf handler is responsible for handling a single u_printf
michael@0 77 * format specification, for example 'd' or 's'.
michael@0 78 * @param stream The UFILE to which to write output.
michael@0 79 * @param info A pointer to a <TT>u_printf_spec_info</TT> struct containing
michael@0 80 * information on the format specification.
michael@0 81 * @param args A pointer to the argument data
michael@0 82 * @return The number of Unicode characters written to <TT>stream</TT>.
michael@0 83 */
michael@0 84 typedef int32_t U_EXPORT2
michael@0 85 u_printf_handler(const u_printf_stream_handler *handler,
michael@0 86
michael@0 87 void *context,
michael@0 88 ULocaleBundle *formatBundle,
michael@0 89 const u_printf_spec_info *info,
michael@0 90 const ufmt_args *args);
michael@0 91
michael@0 92 typedef struct u_printf_info {
michael@0 93 ufmt_type_info info;
michael@0 94 u_printf_handler *handler;
michael@0 95 } u_printf_info;
michael@0 96
michael@0 97 /**
michael@0 98 * Struct encapsulating a single uprintf format specification.
michael@0 99 */
michael@0 100 typedef struct u_printf_spec {
michael@0 101 u_printf_spec_info fInfo; /* Information on this spec */
michael@0 102 int32_t fWidthPos; /* Position of width in arg list */
michael@0 103 int32_t fPrecisionPos; /* Position of precision in arg list */
michael@0 104 int32_t fArgPos; /* Position of data in arg list */
michael@0 105 } u_printf_spec;
michael@0 106
michael@0 107 #define UPRINTF_NUM_FMT_HANDLERS 108
michael@0 108
michael@0 109 /* We do not use handlers for 0-0x1f */
michael@0 110 #define UPRINTF_BASE_FMT_HANDLERS 0x20
michael@0 111
michael@0 112 /* buffer size for formatting */
michael@0 113 #define UPRINTF_BUFFER_SIZE 1024
michael@0 114 #define UPRINTF_SYMBOL_BUFFER_SIZE 8
michael@0 115
michael@0 116 static const UChar gNullStr[] = {0x28, 0x6E, 0x75, 0x6C, 0x6C, 0x29, 0}; /* "(null)" */
michael@0 117 static const UChar gSpaceStr[] = {0x20, 0}; /* " " */
michael@0 118
michael@0 119 /* Sets the sign of a format based on u_printf_spec_info */
michael@0 120 /* TODO: Is setting the prefix symbol to a positive sign a good idea in all locales? */
michael@0 121 static void
michael@0 122 u_printf_set_sign(UNumberFormat *format,
michael@0 123 const u_printf_spec_info *info,
michael@0 124 UChar *prefixBuffer,
michael@0 125 int32_t *prefixBufLen,
michael@0 126 UErrorCode *status)
michael@0 127 {
michael@0 128 if(info->fShowSign) {
michael@0 129 *prefixBufLen = unum_getTextAttribute(format,
michael@0 130 UNUM_POSITIVE_PREFIX,
michael@0 131 prefixBuffer,
michael@0 132 *prefixBufLen,
michael@0 133 status);
michael@0 134 if (info->fSpace) {
michael@0 135 /* Setting UNUM_PLUS_SIGN_SYMBOL affects the exponent too. */
michael@0 136 /* unum_setSymbol(format, UNUM_PLUS_SIGN_SYMBOL, gSpaceStr, 1, &status); */
michael@0 137 unum_setTextAttribute(format, UNUM_POSITIVE_PREFIX, gSpaceStr, 1, status);
michael@0 138 }
michael@0 139 else {
michael@0 140 UChar plusSymbol[UPRINTF_SYMBOL_BUFFER_SIZE];
michael@0 141 int32_t symbolLen;
michael@0 142
michael@0 143 symbolLen = unum_getSymbol(format,
michael@0 144 UNUM_PLUS_SIGN_SYMBOL,
michael@0 145 plusSymbol,
michael@0 146 sizeof(plusSymbol)/sizeof(*plusSymbol),
michael@0 147 status);
michael@0 148 unum_setTextAttribute(format,
michael@0 149 UNUM_POSITIVE_PREFIX,
michael@0 150 plusSymbol,
michael@0 151 symbolLen,
michael@0 152 status);
michael@0 153 }
michael@0 154 }
michael@0 155 else {
michael@0 156 *prefixBufLen = 0;
michael@0 157 }
michael@0 158 }
michael@0 159
michael@0 160 static void
michael@0 161 u_printf_reset_sign(UNumberFormat *format,
michael@0 162 const u_printf_spec_info *info,
michael@0 163 UChar *prefixBuffer,
michael@0 164 int32_t *prefixBufLen,
michael@0 165 UErrorCode *status)
michael@0 166 {
michael@0 167 if(info->fShowSign) {
michael@0 168 unum_setTextAttribute(format,
michael@0 169 UNUM_POSITIVE_PREFIX,
michael@0 170 prefixBuffer,
michael@0 171 *prefixBufLen,
michael@0 172 status);
michael@0 173 }
michael@0 174 }
michael@0 175
michael@0 176
michael@0 177 /* handle a '%' */
michael@0 178 static int32_t
michael@0 179 u_printf_simple_percent_handler(const u_printf_stream_handler *handler,
michael@0 180 void *context,
michael@0 181 ULocaleBundle *formatBundle,
michael@0 182 const u_printf_spec_info *info,
michael@0 183 const ufmt_args *args)
michael@0 184 {
michael@0 185 static const UChar PERCENT[] = { UP_PERCENT };
michael@0 186
michael@0 187 /* put a single '%' onto the output */
michael@0 188 return handler->write(context, PERCENT, 1);
michael@0 189 }
michael@0 190
michael@0 191 /* handle 's' */
michael@0 192 static int32_t
michael@0 193 u_printf_string_handler(const u_printf_stream_handler *handler,
michael@0 194 void *context,
michael@0 195 ULocaleBundle *formatBundle,
michael@0 196 const u_printf_spec_info *info,
michael@0 197 const ufmt_args *args)
michael@0 198 {
michael@0 199 UChar *s;
michael@0 200 UChar buffer[UFMT_DEFAULT_BUFFER_SIZE];
michael@0 201 int32_t len, written;
michael@0 202 int32_t argSize;
michael@0 203 const char *arg = (const char*)(args[0].ptrValue);
michael@0 204
michael@0 205 /* convert from the default codepage to Unicode */
michael@0 206 if (arg) {
michael@0 207 argSize = (int32_t)strlen(arg) + 1;
michael@0 208 if (argSize >= MAX_UCHAR_BUFFER_SIZE(buffer)) {
michael@0 209 s = ufmt_defaultCPToUnicode(arg, argSize,
michael@0 210 (UChar *)uprv_malloc(MAX_UCHAR_BUFFER_NEEDED(argSize)),
michael@0 211 MAX_UCHAR_BUFFER_NEEDED(argSize));
michael@0 212 if(s == NULL) {
michael@0 213 return 0;
michael@0 214 }
michael@0 215 }
michael@0 216 else {
michael@0 217 s = ufmt_defaultCPToUnicode(arg, argSize, buffer,
michael@0 218 sizeof(buffer)/sizeof(UChar));
michael@0 219 }
michael@0 220 }
michael@0 221 else {
michael@0 222 s = (UChar *)gNullStr;
michael@0 223 }
michael@0 224 len = u_strlen(s);
michael@0 225
michael@0 226 /* width = minimum # of characters to write */
michael@0 227 /* precision = maximum # of characters to write */
michael@0 228 if (info->fPrecision != -1 && info->fPrecision < len) {
michael@0 229 len = info->fPrecision;
michael@0 230 }
michael@0 231
michael@0 232 written = handler->pad_and_justify(context, info, s, len);
michael@0 233
michael@0 234 /* clean up */
michael@0 235 if (gNullStr != s && buffer != s) {
michael@0 236 uprv_free(s);
michael@0 237 }
michael@0 238
michael@0 239 return written;
michael@0 240 }
michael@0 241
michael@0 242 static int32_t
michael@0 243 u_printf_char_handler(const u_printf_stream_handler *handler,
michael@0 244 void *context,
michael@0 245 ULocaleBundle *formatBundle,
michael@0 246 const u_printf_spec_info *info,
michael@0 247 const ufmt_args *args)
michael@0 248 {
michael@0 249 UChar s[U16_MAX_LENGTH+1];
michael@0 250 int32_t len = 1, written;
michael@0 251 unsigned char arg = (unsigned char)(args[0].int64Value);
michael@0 252
michael@0 253 /* convert from default codepage to Unicode */
michael@0 254 ufmt_defaultCPToUnicode((const char *)&arg, 2, s, sizeof(s)/sizeof(UChar));
michael@0 255
michael@0 256 /* Remember that this may be an MBCS character */
michael@0 257 if (arg != 0) {
michael@0 258 len = u_strlen(s);
michael@0 259 }
michael@0 260
michael@0 261 /* width = minimum # of characters to write */
michael@0 262 /* precision = maximum # of characters to write */
michael@0 263 /* precision is ignored when handling a char */
michael@0 264
michael@0 265 written = handler->pad_and_justify(context, info, s, len);
michael@0 266
michael@0 267 return written;
michael@0 268 }
michael@0 269
michael@0 270 static int32_t
michael@0 271 u_printf_double_handler(const u_printf_stream_handler *handler,
michael@0 272 void *context,
michael@0 273 ULocaleBundle *formatBundle,
michael@0 274 const u_printf_spec_info *info,
michael@0 275 const ufmt_args *args)
michael@0 276 {
michael@0 277 double num = (double) (args[0].doubleValue);
michael@0 278 UNumberFormat *format;
michael@0 279 UChar result[UPRINTF_BUFFER_SIZE];
michael@0 280 UChar prefixBuffer[UPRINTF_BUFFER_SIZE];
michael@0 281 int32_t prefixBufferLen = sizeof(prefixBuffer);
michael@0 282 int32_t minDecimalDigits;
michael@0 283 int32_t maxDecimalDigits;
michael@0 284 int32_t resultLen;
michael@0 285 UErrorCode status = U_ZERO_ERROR;
michael@0 286
michael@0 287 prefixBuffer[0] = 0;
michael@0 288
michael@0 289 /* mask off any necessary bits */
michael@0 290 /* if(! info->fIsLongDouble)
michael@0 291 num &= DBL_MAX;*/
michael@0 292
michael@0 293 /* get the formatter */
michael@0 294 format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
michael@0 295
michael@0 296 /* handle error */
michael@0 297 if(format == 0)
michael@0 298 return 0;
michael@0 299
michael@0 300 /* save the formatter's state */
michael@0 301 minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
michael@0 302 maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
michael@0 303
michael@0 304 /* set the appropriate flags and number of decimal digits on the formatter */
michael@0 305 if(info->fPrecision != -1) {
michael@0 306 /* set the # of decimal digits */
michael@0 307 unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
michael@0 308 }
michael@0 309 else if(info->fAlt) {
michael@0 310 /* '#' means always show decimal point */
michael@0 311 /* copy of printf behavior on Solaris - '#' shows 6 digits */
michael@0 312 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
michael@0 313 }
michael@0 314 else {
michael@0 315 /* # of decimal digits is 6 if precision not specified regardless of locale */
michael@0 316 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
michael@0 317 }
michael@0 318
michael@0 319 /* set whether to show the sign */
michael@0 320 if (info->fShowSign) {
michael@0 321 u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
michael@0 322 }
michael@0 323
michael@0 324 /* format the number */
michael@0 325 resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
michael@0 326
michael@0 327 if (U_FAILURE(status)) {
michael@0 328 resultLen = 0;
michael@0 329 }
michael@0 330
michael@0 331 /* restore the number format */
michael@0 332 /* TODO: Is this needed? */
michael@0 333 unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
michael@0 334 unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
michael@0 335
michael@0 336 if (info->fShowSign) {
michael@0 337 /* Reset back to original value regardless of what the error was */
michael@0 338 UErrorCode localStatus = U_ZERO_ERROR;
michael@0 339 u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
michael@0 340 }
michael@0 341
michael@0 342 return handler->pad_and_justify(context, info, result, resultLen);
michael@0 343 }
michael@0 344
michael@0 345 /* HSYS */
michael@0 346 static int32_t
michael@0 347 u_printf_integer_handler(const u_printf_stream_handler *handler,
michael@0 348 void *context,
michael@0 349 ULocaleBundle *formatBundle,
michael@0 350 const u_printf_spec_info *info,
michael@0 351 const ufmt_args *args)
michael@0 352 {
michael@0 353 int64_t num = args[0].int64Value;
michael@0 354 UNumberFormat *format;
michael@0 355 UChar result[UPRINTF_BUFFER_SIZE];
michael@0 356 UChar prefixBuffer[UPRINTF_BUFFER_SIZE];
michael@0 357 int32_t prefixBufferLen = sizeof(prefixBuffer);
michael@0 358 int32_t minDigits = -1;
michael@0 359 int32_t resultLen;
michael@0 360 UErrorCode status = U_ZERO_ERROR;
michael@0 361
michael@0 362 prefixBuffer[0] = 0;
michael@0 363
michael@0 364 /* mask off any necessary bits */
michael@0 365 if (info->fIsShort)
michael@0 366 num = (int16_t)num;
michael@0 367 else if (!info->fIsLongLong)
michael@0 368 num = (int32_t)num;
michael@0 369
michael@0 370 /* get the formatter */
michael@0 371 format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
michael@0 372
michael@0 373 /* handle error */
michael@0 374 if(format == 0)
michael@0 375 return 0;
michael@0 376
michael@0 377 /* set the appropriate flags on the formatter */
michael@0 378
michael@0 379 /* set the minimum integer digits */
michael@0 380 if(info->fPrecision != -1) {
michael@0 381 /* set the minimum # of digits */
michael@0 382 minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
michael@0 383 unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
michael@0 384 }
michael@0 385
michael@0 386 /* set whether to show the sign */
michael@0 387 if(info->fShowSign) {
michael@0 388 u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
michael@0 389 }
michael@0 390
michael@0 391 /* format the number */
michael@0 392 resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
michael@0 393
michael@0 394 if (U_FAILURE(status)) {
michael@0 395 resultLen = 0;
michael@0 396 }
michael@0 397
michael@0 398 /* restore the number format */
michael@0 399 if (minDigits != -1) {
michael@0 400 unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
michael@0 401 }
michael@0 402
michael@0 403 if (info->fShowSign) {
michael@0 404 /* Reset back to original value regardless of what the error was */
michael@0 405 UErrorCode localStatus = U_ZERO_ERROR;
michael@0 406 u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
michael@0 407 }
michael@0 408
michael@0 409 return handler->pad_and_justify(context, info, result, resultLen);
michael@0 410 }
michael@0 411
michael@0 412 static int32_t
michael@0 413 u_printf_hex_handler(const u_printf_stream_handler *handler,
michael@0 414 void *context,
michael@0 415 ULocaleBundle *formatBundle,
michael@0 416 const u_printf_spec_info *info,
michael@0 417 const ufmt_args *args)
michael@0 418 {
michael@0 419 int64_t num = args[0].int64Value;
michael@0 420 UChar result[UPRINTF_BUFFER_SIZE];
michael@0 421 int32_t len = UPRINTF_BUFFER_SIZE;
michael@0 422
michael@0 423
michael@0 424 /* mask off any necessary bits */
michael@0 425 if (info->fIsShort)
michael@0 426 num &= UINT16_MAX;
michael@0 427 else if (!info->fIsLongLong)
michael@0 428 num &= UINT32_MAX;
michael@0 429
michael@0 430 /* format the number, preserving the minimum # of digits */
michael@0 431 ufmt_64tou(result, &len, num, 16,
michael@0 432 (UBool)(info->fSpec == 0x0078),
michael@0 433 (info->fPrecision == -1 && info->fZero) ? info->fWidth : info->fPrecision);
michael@0 434
michael@0 435 /* convert to alt form, if desired */
michael@0 436 if(num != 0 && info->fAlt && len < UPRINTF_BUFFER_SIZE - 2) {
michael@0 437 /* shift the formatted string right by 2 chars */
michael@0 438 memmove(result + 2, result, len * sizeof(UChar));
michael@0 439 result[0] = 0x0030;
michael@0 440 result[1] = info->fSpec;
michael@0 441 len += 2;
michael@0 442 }
michael@0 443
michael@0 444 return handler->pad_and_justify(context, info, result, len);
michael@0 445 }
michael@0 446
michael@0 447 static int32_t
michael@0 448 u_printf_octal_handler(const u_printf_stream_handler *handler,
michael@0 449 void *context,
michael@0 450 ULocaleBundle *formatBundle,
michael@0 451 const u_printf_spec_info *info,
michael@0 452 const ufmt_args *args)
michael@0 453 {
michael@0 454 int64_t num = args[0].int64Value;
michael@0 455 UChar result[UPRINTF_BUFFER_SIZE];
michael@0 456 int32_t len = UPRINTF_BUFFER_SIZE;
michael@0 457
michael@0 458
michael@0 459 /* mask off any necessary bits */
michael@0 460 if (info->fIsShort)
michael@0 461 num &= UINT16_MAX;
michael@0 462 else if (!info->fIsLongLong)
michael@0 463 num &= UINT32_MAX;
michael@0 464
michael@0 465 /* format the number, preserving the minimum # of digits */
michael@0 466 ufmt_64tou(result, &len, num, 8,
michael@0 467 FALSE, /* doesn't matter for octal */
michael@0 468 info->fPrecision == -1 && info->fZero ? info->fWidth : info->fPrecision);
michael@0 469
michael@0 470 /* convert to alt form, if desired */
michael@0 471 if(info->fAlt && result[0] != 0x0030 && len < UPRINTF_BUFFER_SIZE - 1) {
michael@0 472 /* shift the formatted string right by 1 char */
michael@0 473 memmove(result + 1, result, len * sizeof(UChar));
michael@0 474 result[0] = 0x0030;
michael@0 475 len += 1;
michael@0 476 }
michael@0 477
michael@0 478 return handler->pad_and_justify(context, info, result, len);
michael@0 479 }
michael@0 480
michael@0 481 static int32_t
michael@0 482 u_printf_uinteger_handler(const u_printf_stream_handler *handler,
michael@0 483 void *context,
michael@0 484 ULocaleBundle *formatBundle,
michael@0 485 const u_printf_spec_info *info,
michael@0 486 const ufmt_args *args)
michael@0 487 {
michael@0 488 int64_t num = args[0].int64Value;
michael@0 489 UNumberFormat *format;
michael@0 490 UChar result[UPRINTF_BUFFER_SIZE];
michael@0 491 int32_t minDigits = -1;
michael@0 492 int32_t resultLen;
michael@0 493 UErrorCode status = U_ZERO_ERROR;
michael@0 494
michael@0 495 /* TODO: Fix this once uint64_t can be formatted. */
michael@0 496 if (info->fIsShort)
michael@0 497 num &= UINT16_MAX;
michael@0 498 else if (!info->fIsLongLong)
michael@0 499 num &= UINT32_MAX;
michael@0 500
michael@0 501 /* get the formatter */
michael@0 502 format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
michael@0 503
michael@0 504 /* handle error */
michael@0 505 if(format == 0)
michael@0 506 return 0;
michael@0 507
michael@0 508 /* set the appropriate flags on the formatter */
michael@0 509
michael@0 510 /* set the minimum integer digits */
michael@0 511 if(info->fPrecision != -1) {
michael@0 512 /* set the minimum # of digits */
michael@0 513 minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
michael@0 514 unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
michael@0 515 }
michael@0 516
michael@0 517 /* To mirror other stdio implementations, we ignore the sign argument */
michael@0 518
michael@0 519 /* format the number */
michael@0 520 resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
michael@0 521
michael@0 522 if (U_FAILURE(status)) {
michael@0 523 resultLen = 0;
michael@0 524 }
michael@0 525
michael@0 526 /* restore the number format */
michael@0 527 if (minDigits != -1) {
michael@0 528 unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
michael@0 529 }
michael@0 530
michael@0 531 return handler->pad_and_justify(context, info, result, resultLen);
michael@0 532 }
michael@0 533
michael@0 534 static int32_t
michael@0 535 u_printf_pointer_handler(const u_printf_stream_handler *handler,
michael@0 536 void *context,
michael@0 537 ULocaleBundle *formatBundle,
michael@0 538 const u_printf_spec_info *info,
michael@0 539 const ufmt_args *args)
michael@0 540 {
michael@0 541 UChar result[UPRINTF_BUFFER_SIZE];
michael@0 542 int32_t len = UPRINTF_BUFFER_SIZE;
michael@0 543
michael@0 544 /* format the pointer in hex */
michael@0 545 ufmt_ptou(result, &len, args[0].ptrValue, TRUE/*, info->fPrecision*/);
michael@0 546
michael@0 547 return handler->pad_and_justify(context, info, result, len);
michael@0 548 }
michael@0 549
michael@0 550 static int32_t
michael@0 551 u_printf_scientific_handler(const u_printf_stream_handler *handler,
michael@0 552 void *context,
michael@0 553 ULocaleBundle *formatBundle,
michael@0 554 const u_printf_spec_info *info,
michael@0 555 const ufmt_args *args)
michael@0 556 {
michael@0 557 double num = (double) (args[0].doubleValue);
michael@0 558 UNumberFormat *format;
michael@0 559 UChar result[UPRINTF_BUFFER_SIZE];
michael@0 560 UChar prefixBuffer[UPRINTF_BUFFER_SIZE];
michael@0 561 int32_t prefixBufferLen = sizeof(prefixBuffer);
michael@0 562 int32_t minDecimalDigits;
michael@0 563 int32_t maxDecimalDigits;
michael@0 564 UErrorCode status = U_ZERO_ERROR;
michael@0 565 UChar srcExpBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
michael@0 566 int32_t srcLen, expLen;
michael@0 567 int32_t resultLen;
michael@0 568 UChar expBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
michael@0 569
michael@0 570 prefixBuffer[0] = 0;
michael@0 571
michael@0 572 /* mask off any necessary bits */
michael@0 573 /* if(! info->fIsLongDouble)
michael@0 574 num &= DBL_MAX;*/
michael@0 575
michael@0 576 /* get the formatter */
michael@0 577 format = u_locbund_getNumberFormat(formatBundle, UNUM_SCIENTIFIC);
michael@0 578
michael@0 579 /* handle error */
michael@0 580 if(format == 0)
michael@0 581 return 0;
michael@0 582
michael@0 583 /* set the appropriate flags on the formatter */
michael@0 584
michael@0 585 srcLen = unum_getSymbol(format,
michael@0 586 UNUM_EXPONENTIAL_SYMBOL,
michael@0 587 srcExpBuf,
michael@0 588 sizeof(srcExpBuf),
michael@0 589 &status);
michael@0 590
michael@0 591 /* Upper/lower case the e */
michael@0 592 if (info->fSpec == (UChar)0x65 /* e */) {
michael@0 593 expLen = u_strToLower(expBuf, (int32_t)sizeof(expBuf),
michael@0 594 srcExpBuf, srcLen,
michael@0 595 formatBundle->fLocale,
michael@0 596 &status);
michael@0 597 }
michael@0 598 else {
michael@0 599 expLen = u_strToUpper(expBuf, (int32_t)sizeof(expBuf),
michael@0 600 srcExpBuf, srcLen,
michael@0 601 formatBundle->fLocale,
michael@0 602 &status);
michael@0 603 }
michael@0 604
michael@0 605 unum_setSymbol(format,
michael@0 606 UNUM_EXPONENTIAL_SYMBOL,
michael@0 607 expBuf,
michael@0 608 expLen,
michael@0 609 &status);
michael@0 610
michael@0 611 /* save the formatter's state */
michael@0 612 minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
michael@0 613 maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
michael@0 614
michael@0 615 /* set the appropriate flags and number of decimal digits on the formatter */
michael@0 616 if(info->fPrecision != -1) {
michael@0 617 /* set the # of decimal digits */
michael@0 618 if (info->fOrigSpec == (UChar)0x65 /* e */ || info->fOrigSpec == (UChar)0x45 /* E */) {
michael@0 619 unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
michael@0 620 }
michael@0 621 else {
michael@0 622 unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, 1);
michael@0 623 unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, info->fPrecision);
michael@0 624 }
michael@0 625 }
michael@0 626 else if(info->fAlt) {
michael@0 627 /* '#' means always show decimal point */
michael@0 628 /* copy of printf behavior on Solaris - '#' shows 6 digits */
michael@0 629 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
michael@0 630 }
michael@0 631 else {
michael@0 632 /* # of decimal digits is 6 if precision not specified */
michael@0 633 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
michael@0 634 }
michael@0 635
michael@0 636 /* set whether to show the sign */
michael@0 637 if (info->fShowSign) {
michael@0 638 u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
michael@0 639 }
michael@0 640
michael@0 641 /* format the number */
michael@0 642 resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
michael@0 643
michael@0 644 if (U_FAILURE(status)) {
michael@0 645 resultLen = 0;
michael@0 646 }
michael@0 647
michael@0 648 /* restore the number format */
michael@0 649 /* TODO: Is this needed? */
michael@0 650 unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
michael@0 651 unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
michael@0 652
michael@0 653 /* Since we're the only one using the scientific
michael@0 654 format, we don't need to save the old exponent value. */
michael@0 655 /*unum_setSymbol(format,
michael@0 656 UNUM_EXPONENTIAL_SYMBOL,
michael@0 657 srcExpBuf,
michael@0 658 srcLen,
michael@0 659 &status);*/
michael@0 660
michael@0 661 if (info->fShowSign) {
michael@0 662 /* Reset back to original value regardless of what the error was */
michael@0 663 UErrorCode localStatus = U_ZERO_ERROR;
michael@0 664 u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
michael@0 665 }
michael@0 666
michael@0 667 return handler->pad_and_justify(context, info, result, resultLen);
michael@0 668 }
michael@0 669
michael@0 670 static int32_t
michael@0 671 u_printf_percent_handler(const u_printf_stream_handler *handler,
michael@0 672 void *context,
michael@0 673 ULocaleBundle *formatBundle,
michael@0 674 const u_printf_spec_info *info,
michael@0 675 const ufmt_args *args)
michael@0 676 {
michael@0 677 double num = (double) (args[0].doubleValue);
michael@0 678 UNumberFormat *format;
michael@0 679 UChar result[UPRINTF_BUFFER_SIZE];
michael@0 680 UChar prefixBuffer[UPRINTF_BUFFER_SIZE];
michael@0 681 int32_t prefixBufferLen = sizeof(prefixBuffer);
michael@0 682 int32_t minDecimalDigits;
michael@0 683 int32_t maxDecimalDigits;
michael@0 684 int32_t resultLen;
michael@0 685 UErrorCode status = U_ZERO_ERROR;
michael@0 686
michael@0 687 prefixBuffer[0] = 0;
michael@0 688
michael@0 689 /* mask off any necessary bits */
michael@0 690 /* if(! info->fIsLongDouble)
michael@0 691 num &= DBL_MAX;*/
michael@0 692
michael@0 693 /* get the formatter */
michael@0 694 format = u_locbund_getNumberFormat(formatBundle, UNUM_PERCENT);
michael@0 695
michael@0 696 /* handle error */
michael@0 697 if(format == 0)
michael@0 698 return 0;
michael@0 699
michael@0 700 /* save the formatter's state */
michael@0 701 minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
michael@0 702 maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
michael@0 703
michael@0 704 /* set the appropriate flags and number of decimal digits on the formatter */
michael@0 705 if(info->fPrecision != -1) {
michael@0 706 /* set the # of decimal digits */
michael@0 707 unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
michael@0 708 }
michael@0 709 else if(info->fAlt) {
michael@0 710 /* '#' means always show decimal point */
michael@0 711 /* copy of printf behavior on Solaris - '#' shows 6 digits */
michael@0 712 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
michael@0 713 }
michael@0 714 else {
michael@0 715 /* # of decimal digits is 6 if precision not specified */
michael@0 716 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
michael@0 717 }
michael@0 718
michael@0 719 /* set whether to show the sign */
michael@0 720 if (info->fShowSign) {
michael@0 721 u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
michael@0 722 }
michael@0 723
michael@0 724 /* format the number */
michael@0 725 resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
michael@0 726
michael@0 727 if (U_FAILURE(status)) {
michael@0 728 resultLen = 0;
michael@0 729 }
michael@0 730
michael@0 731 /* restore the number format */
michael@0 732 /* TODO: Is this needed? */
michael@0 733 unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
michael@0 734 unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
michael@0 735
michael@0 736 if (info->fShowSign) {
michael@0 737 /* Reset back to original value regardless of what the error was */
michael@0 738 UErrorCode localStatus = U_ZERO_ERROR;
michael@0 739 u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
michael@0 740 }
michael@0 741
michael@0 742 return handler->pad_and_justify(context, info, result, resultLen);
michael@0 743 }
michael@0 744
michael@0 745 static int32_t
michael@0 746 u_printf_ustring_handler(const u_printf_stream_handler *handler,
michael@0 747 void *context,
michael@0 748 ULocaleBundle *formatBundle,
michael@0 749 const u_printf_spec_info *info,
michael@0 750 const ufmt_args *args)
michael@0 751 {
michael@0 752 int32_t len, written;
michael@0 753 const UChar *arg = (const UChar*)(args[0].ptrValue);
michael@0 754
michael@0 755 /* allocate enough space for the buffer */
michael@0 756 if (arg == NULL) {
michael@0 757 arg = gNullStr;
michael@0 758 }
michael@0 759 len = u_strlen(arg);
michael@0 760
michael@0 761 /* width = minimum # of characters to write */
michael@0 762 /* precision = maximum # of characters to write */
michael@0 763 if (info->fPrecision != -1 && info->fPrecision < len) {
michael@0 764 len = info->fPrecision;
michael@0 765 }
michael@0 766
michael@0 767 /* determine if the string should be padded */
michael@0 768 written = handler->pad_and_justify(context, info, arg, len);
michael@0 769
michael@0 770 return written;
michael@0 771 }
michael@0 772
michael@0 773 static int32_t
michael@0 774 u_printf_uchar_handler(const u_printf_stream_handler *handler,
michael@0 775 void *context,
michael@0 776 ULocaleBundle *formatBundle,
michael@0 777 const u_printf_spec_info *info,
michael@0 778 const ufmt_args *args)
michael@0 779 {
michael@0 780 int32_t written = 0;
michael@0 781 UChar arg = (UChar)(args[0].int64Value);
michael@0 782
michael@0 783 /* width = minimum # of characters to write */
michael@0 784 /* precision = maximum # of characters to write */
michael@0 785 /* precision is ignored when handling a uchar */
michael@0 786
michael@0 787 /* determine if the string should be padded */
michael@0 788 written = handler->pad_and_justify(context, info, &arg, 1);
michael@0 789
michael@0 790 return written;
michael@0 791 }
michael@0 792
michael@0 793 static int32_t
michael@0 794 u_printf_scidbl_handler(const u_printf_stream_handler *handler,
michael@0 795 void *context,
michael@0 796 ULocaleBundle *formatBundle,
michael@0 797 const u_printf_spec_info *info,
michael@0 798 const ufmt_args *args)
michael@0 799 {
michael@0 800 u_printf_spec_info scidbl_info;
michael@0 801 double num = args[0].doubleValue;
michael@0 802 int32_t retVal;
michael@0 803 UNumberFormat *format;
michael@0 804 int32_t maxSigDecimalDigits, significantDigits;
michael@0 805
michael@0 806 memcpy(&scidbl_info, info, sizeof(u_printf_spec_info));
michael@0 807
michael@0 808 /* determine whether to use 'd', 'e' or 'f' notation */
michael@0 809 if (scidbl_info.fPrecision == -1 && num == uprv_trunc(num))
michael@0 810 {
michael@0 811 /* use 'f' notation */
michael@0 812 scidbl_info.fSpec = 0x0066;
michael@0 813 scidbl_info.fPrecision = 0;
michael@0 814 /* call the double handler */
michael@0 815 retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args);
michael@0 816 }
michael@0 817 else if(num < 0.0001 || (scidbl_info.fPrecision < 1 && 1000000.0 <= num)
michael@0 818 || (scidbl_info.fPrecision != -1 && num > uprv_pow10(scidbl_info.fPrecision)))
michael@0 819 {
michael@0 820 /* use 'e' or 'E' notation */
michael@0 821 scidbl_info.fSpec = scidbl_info.fSpec - 2;
michael@0 822 if (scidbl_info.fPrecision == -1) {
michael@0 823 scidbl_info.fPrecision = 5;
michael@0 824 }
michael@0 825 /* call the scientific handler */
michael@0 826 retVal = u_printf_scientific_handler(handler, context, formatBundle, &scidbl_info, args);
michael@0 827 }
michael@0 828 else {
michael@0 829 format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
michael@0 830 /* Check for null pointer */
michael@0 831 if (format == NULL) {
michael@0 832 return 0;
michael@0 833 }
michael@0 834 maxSigDecimalDigits = unum_getAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS);
michael@0 835 significantDigits = scidbl_info.fPrecision;
michael@0 836
michael@0 837 /* use 'f' notation */
michael@0 838 scidbl_info.fSpec = 0x0066;
michael@0 839 if (significantDigits == -1) {
michael@0 840 significantDigits = 6;
michael@0 841 }
michael@0 842 unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, TRUE);
michael@0 843 unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, significantDigits);
michael@0 844 /* call the double handler */
michael@0 845 retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args);
michael@0 846 unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, maxSigDecimalDigits);
michael@0 847 unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, FALSE);
michael@0 848 }
michael@0 849 return retVal;
michael@0 850 }
michael@0 851
michael@0 852 static int32_t
michael@0 853 u_printf_count_handler(const u_printf_stream_handler *handler,
michael@0 854 void *context,
michael@0 855 ULocaleBundle *formatBundle,
michael@0 856 const u_printf_spec_info *info,
michael@0 857 const ufmt_args *args)
michael@0 858 {
michael@0 859 int32_t *count = (int32_t*)(args[0].ptrValue);
michael@0 860
michael@0 861 /* in the special case of count, the u_printf_spec_info's width */
michael@0 862 /* will contain the # of chars written thus far */
michael@0 863 *count = info->fWidth;
michael@0 864
michael@0 865 return 0;
michael@0 866 }
michael@0 867
michael@0 868 static int32_t
michael@0 869 u_printf_spellout_handler(const u_printf_stream_handler *handler,
michael@0 870 void *context,
michael@0 871 ULocaleBundle *formatBundle,
michael@0 872 const u_printf_spec_info *info,
michael@0 873 const ufmt_args *args)
michael@0 874 {
michael@0 875 double num = (double) (args[0].doubleValue);
michael@0 876 UNumberFormat *format;
michael@0 877 UChar result[UPRINTF_BUFFER_SIZE];
michael@0 878 UChar prefixBuffer[UPRINTF_BUFFER_SIZE];
michael@0 879 int32_t prefixBufferLen = sizeof(prefixBuffer);
michael@0 880 int32_t minDecimalDigits;
michael@0 881 int32_t maxDecimalDigits;
michael@0 882 int32_t resultLen;
michael@0 883 UErrorCode status = U_ZERO_ERROR;
michael@0 884
michael@0 885 prefixBuffer[0] = 0;
michael@0 886
michael@0 887 /* mask off any necessary bits */
michael@0 888 /* if(! info->fIsLongDouble)
michael@0 889 num &= DBL_MAX;*/
michael@0 890
michael@0 891 /* get the formatter */
michael@0 892 format = u_locbund_getNumberFormat(formatBundle, UNUM_SPELLOUT);
michael@0 893
michael@0 894 /* handle error */
michael@0 895 if(format == 0)
michael@0 896 return 0;
michael@0 897
michael@0 898 /* save the formatter's state */
michael@0 899 minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
michael@0 900 maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
michael@0 901
michael@0 902 /* set the appropriate flags and number of decimal digits on the formatter */
michael@0 903 if(info->fPrecision != -1) {
michael@0 904 /* set the # of decimal digits */
michael@0 905 unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
michael@0 906 }
michael@0 907 else if(info->fAlt) {
michael@0 908 /* '#' means always show decimal point */
michael@0 909 /* copy of printf behavior on Solaris - '#' shows 6 digits */
michael@0 910 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
michael@0 911 }
michael@0 912 else {
michael@0 913 /* # of decimal digits is 6 if precision not specified */
michael@0 914 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
michael@0 915 }
michael@0 916
michael@0 917 /* set whether to show the sign */
michael@0 918 if (info->fShowSign) {
michael@0 919 u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
michael@0 920 }
michael@0 921
michael@0 922 /* format the number */
michael@0 923 resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
michael@0 924
michael@0 925 if (U_FAILURE(status)) {
michael@0 926 resultLen = 0;
michael@0 927 }
michael@0 928
michael@0 929 /* restore the number format */
michael@0 930 /* TODO: Is this needed? */
michael@0 931 unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
michael@0 932 unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
michael@0 933
michael@0 934 if (info->fShowSign) {
michael@0 935 /* Reset back to original value regardless of what the error was */
michael@0 936 UErrorCode localStatus = U_ZERO_ERROR;
michael@0 937 u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
michael@0 938 }
michael@0 939
michael@0 940 return handler->pad_and_justify(context, info, result, resultLen);
michael@0 941 }
michael@0 942
michael@0 943 /* Use US-ASCII characters only for formatting. Most codepages have
michael@0 944 characters 20-7F from Unicode. Using any other codepage specific
michael@0 945 characters will make it very difficult to format the string on
michael@0 946 non-Unicode machines */
michael@0 947 static const u_printf_info g_u_printf_infos[UPRINTF_NUM_FMT_HANDLERS] = {
michael@0 948 /* 0x20 */
michael@0 949 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
michael@0 950 UFMT_EMPTY, UFMT_SIMPLE_PERCENT,UFMT_EMPTY, UFMT_EMPTY,
michael@0 951 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
michael@0 952 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
michael@0 953
michael@0 954 /* 0x30 */
michael@0 955 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
michael@0 956 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
michael@0 957 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
michael@0 958 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
michael@0 959
michael@0 960 /* 0x40 */
michael@0 961 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_UCHAR,
michael@0 962 UFMT_EMPTY, UFMT_SCIENTIFIC, UFMT_EMPTY, UFMT_SCIDBL,
michael@0 963 #ifdef U_USE_OBSOLETE_IO_FORMATTING
michael@0 964 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_UCHAR/*deprecated*/,
michael@0 965 #else
michael@0 966 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
michael@0 967 #endif
michael@0 968 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
michael@0 969
michael@0 970 /* 0x50 */
michael@0 971 UFMT_PERCENT, UFMT_EMPTY, UFMT_EMPTY, UFMT_USTRING,
michael@0 972 #ifdef U_USE_OBSOLETE_IO_FORMATTING
michael@0 973 UFMT_EMPTY, UFMT_USTRING/*deprecated*/,UFMT_SPELLOUT, UFMT_EMPTY,
michael@0 974 #else
michael@0 975 UFMT_EMPTY, UFMT_EMPTY, UFMT_SPELLOUT, UFMT_EMPTY,
michael@0 976 #endif
michael@0 977 UFMT_HEX, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
michael@0 978 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
michael@0 979
michael@0 980 /* 0x60 */
michael@0 981 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_CHAR,
michael@0 982 UFMT_INT, UFMT_SCIENTIFIC, UFMT_DOUBLE, UFMT_SCIDBL,
michael@0 983 UFMT_EMPTY, UFMT_INT, UFMT_EMPTY, UFMT_EMPTY,
michael@0 984 UFMT_EMPTY, UFMT_EMPTY, UFMT_COUNT, UFMT_OCTAL,
michael@0 985
michael@0 986 /* 0x70 */
michael@0 987 UFMT_POINTER, UFMT_EMPTY, UFMT_EMPTY, UFMT_STRING,
michael@0 988 UFMT_EMPTY, UFMT_UINT, UFMT_EMPTY, UFMT_EMPTY,
michael@0 989 UFMT_HEX, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
michael@0 990 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY,
michael@0 991 };
michael@0 992
michael@0 993 /* flag characters for uprintf */
michael@0 994 #define FLAG_MINUS 0x002D
michael@0 995 #define FLAG_PLUS 0x002B
michael@0 996 #define FLAG_SPACE 0x0020
michael@0 997 #define FLAG_POUND 0x0023
michael@0 998 #define FLAG_ZERO 0x0030
michael@0 999 #define FLAG_PAREN 0x0028
michael@0 1000
michael@0 1001 #define ISFLAG(s) (s) == FLAG_MINUS || \
michael@0 1002 (s) == FLAG_PLUS || \
michael@0 1003 (s) == FLAG_SPACE || \
michael@0 1004 (s) == FLAG_POUND || \
michael@0 1005 (s) == FLAG_ZERO || \
michael@0 1006 (s) == FLAG_PAREN
michael@0 1007
michael@0 1008 /* special characters for uprintf */
michael@0 1009 #define SPEC_ASTERISK 0x002A
michael@0 1010 #define SPEC_DOLLARSIGN 0x0024
michael@0 1011 #define SPEC_PERIOD 0x002E
michael@0 1012 #define SPEC_PERCENT 0x0025
michael@0 1013
michael@0 1014 /* unicode digits */
michael@0 1015 #define DIGIT_ZERO 0x0030
michael@0 1016 #define DIGIT_ONE 0x0031
michael@0 1017 #define DIGIT_TWO 0x0032
michael@0 1018 #define DIGIT_THREE 0x0033
michael@0 1019 #define DIGIT_FOUR 0x0034
michael@0 1020 #define DIGIT_FIVE 0x0035
michael@0 1021 #define DIGIT_SIX 0x0036
michael@0 1022 #define DIGIT_SEVEN 0x0037
michael@0 1023 #define DIGIT_EIGHT 0x0038
michael@0 1024 #define DIGIT_NINE 0x0039
michael@0 1025
michael@0 1026 #define ISDIGIT(s) (s) == DIGIT_ZERO || \
michael@0 1027 (s) == DIGIT_ONE || \
michael@0 1028 (s) == DIGIT_TWO || \
michael@0 1029 (s) == DIGIT_THREE || \
michael@0 1030 (s) == DIGIT_FOUR || \
michael@0 1031 (s) == DIGIT_FIVE || \
michael@0 1032 (s) == DIGIT_SIX || \
michael@0 1033 (s) == DIGIT_SEVEN || \
michael@0 1034 (s) == DIGIT_EIGHT || \
michael@0 1035 (s) == DIGIT_NINE
michael@0 1036
michael@0 1037 /* u_printf modifiers */
michael@0 1038 #define MOD_H 0x0068
michael@0 1039 #define MOD_LOWERL 0x006C
michael@0 1040 #define MOD_L 0x004C
michael@0 1041
michael@0 1042 #define ISMOD(s) (s) == MOD_H || \
michael@0 1043 (s) == MOD_LOWERL || \
michael@0 1044 (s) == MOD_L
michael@0 1045 /* Returns an array of the parsed argument type given in the format string. */
michael@0 1046 static ufmt_args* parseArguments(const UChar *alias, va_list ap, UErrorCode *status) {
michael@0 1047 ufmt_args *arglist = NULL;
michael@0 1048 ufmt_type_info *typelist = NULL;
michael@0 1049 UBool *islonglong = NULL;
michael@0 1050 int32_t size = 0;
michael@0 1051 int32_t pos = 0;
michael@0 1052 UChar type;
michael@0 1053 uint16_t handlerNum;
michael@0 1054 const UChar *aliasStart = alias;
michael@0 1055
michael@0 1056 /* get maximum number of arguments */
michael@0 1057 for(;;) {
michael@0 1058 /* find % */
michael@0 1059 while(*alias != UP_PERCENT && *alias != 0x0000) {
michael@0 1060 alias++;
michael@0 1061 }
michael@0 1062
michael@0 1063 if(*alias == 0x0000) {
michael@0 1064 break;
michael@0 1065 }
michael@0 1066
michael@0 1067 alias++;
michael@0 1068
michael@0 1069 /* handle the pos number */
michael@0 1070 if(ISDIGIT(*alias)) {
michael@0 1071
michael@0 1072 /* handle positional parameters */
michael@0 1073 if(ISDIGIT(*alias)) {
michael@0 1074 pos = (int) (*alias++ - DIGIT_ZERO);
michael@0 1075
michael@0 1076 while(ISDIGIT(*alias)) {
michael@0 1077 pos *= 10;
michael@0 1078 pos += (int) (*alias++ - DIGIT_ZERO);
michael@0 1079 }
michael@0 1080 }
michael@0 1081
michael@0 1082 /* if there is no '$', don't read anything */
michael@0 1083 if(*alias != SPEC_DOLLARSIGN) {
michael@0 1084 return NULL;
michael@0 1085 }
michael@0 1086 } else {
michael@0 1087 return NULL;
michael@0 1088 }
michael@0 1089
michael@0 1090 if (pos > size) {
michael@0 1091 size = pos;
michael@0 1092 }
michael@0 1093 }
michael@0 1094
michael@0 1095 /* create the parsed argument list */
michael@0 1096 typelist = (ufmt_type_info*)uprv_malloc(sizeof(ufmt_type_info) * size);
michael@0 1097 islonglong = (UBool*)uprv_malloc(sizeof(UBool) * size);
michael@0 1098 arglist = (ufmt_args*)uprv_malloc(sizeof(ufmt_args) * size);
michael@0 1099
michael@0 1100 /* If malloc failed, return NULL */
michael@0 1101 if (!typelist || !islonglong || !arglist) {
michael@0 1102 if (typelist) {
michael@0 1103 uprv_free(typelist);
michael@0 1104 }
michael@0 1105
michael@0 1106 if (islonglong) {
michael@0 1107 uprv_free(islonglong);
michael@0 1108 }
michael@0 1109
michael@0 1110 if (arglist) {
michael@0 1111 uprv_free(arglist);
michael@0 1112 }
michael@0 1113
michael@0 1114 *status = U_MEMORY_ALLOCATION_ERROR;
michael@0 1115 return NULL;
michael@0 1116 }
michael@0 1117
michael@0 1118 /* reset alias back to the beginning */
michael@0 1119 alias = aliasStart;
michael@0 1120
michael@0 1121 for(;;) {
michael@0 1122 /* find % */
michael@0 1123 while(*alias != UP_PERCENT && *alias != 0x0000) {
michael@0 1124 alias++;
michael@0 1125 }
michael@0 1126
michael@0 1127 if(*alias == 0x0000) {
michael@0 1128 break;
michael@0 1129 }
michael@0 1130
michael@0 1131 alias++;
michael@0 1132
michael@0 1133 /* handle positional parameters */
michael@0 1134 if(ISDIGIT(*alias)) {
michael@0 1135 pos = (int) (*alias++ - DIGIT_ZERO);
michael@0 1136
michael@0 1137 while(ISDIGIT(*alias)) {
michael@0 1138 pos *= 10;
michael@0 1139 pos += (int) (*alias++ - DIGIT_ZERO);
michael@0 1140 }
michael@0 1141 }
michael@0 1142 /* offset position by 1 */
michael@0 1143 pos--;
michael@0 1144
michael@0 1145 /* skip over everything except for the type */
michael@0 1146 while (ISMOD(*alias) || ISFLAG(*alias) || ISDIGIT(*alias) ||
michael@0 1147 *alias == SPEC_ASTERISK || *alias == SPEC_PERIOD || *alias == SPEC_DOLLARSIGN) {
michael@0 1148 islonglong[pos] = FALSE;
michael@0 1149 if (ISMOD(*alias)) {
michael@0 1150 alias++;
michael@0 1151 if (*alias == MOD_LOWERL) {
michael@0 1152 islonglong[pos] = TRUE;
michael@0 1153 }
michael@0 1154 }
michael@0 1155 alias++;
michael@0 1156 }
michael@0 1157 type = *alias;
michael@0 1158
michael@0 1159 /* store the argument type in the correct position of the parsed argument list */
michael@0 1160 handlerNum = (uint16_t)(type - UPRINTF_BASE_FMT_HANDLERS);
michael@0 1161 if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) {
michael@0 1162 typelist[pos] = g_u_printf_infos[ handlerNum ].info;
michael@0 1163 } else {
michael@0 1164 typelist[pos] = ufmt_empty;
michael@0 1165 }
michael@0 1166 }
michael@0 1167
michael@0 1168 /* store argument in arglist */
michael@0 1169 for (pos = 0; pos < size; pos++) {
michael@0 1170 switch (typelist[pos]) {
michael@0 1171 case ufmt_string:
michael@0 1172 case ufmt_ustring:
michael@0 1173 case ufmt_pointer:
michael@0 1174 arglist[pos].ptrValue = va_arg(ap, void*);
michael@0 1175 break;
michael@0 1176 case ufmt_char:
michael@0 1177 case ufmt_uchar:
michael@0 1178 case ufmt_int:
michael@0 1179 if (islonglong[pos]) {
michael@0 1180 arglist[pos].int64Value = va_arg(ap, int64_t);
michael@0 1181 }
michael@0 1182 else {
michael@0 1183 arglist[pos].int64Value = va_arg(ap, int32_t);
michael@0 1184 }
michael@0 1185 break;
michael@0 1186 case ufmt_float:
michael@0 1187 arglist[pos].floatValue = (float) va_arg(ap, double);
michael@0 1188 break;
michael@0 1189 case ufmt_double:
michael@0 1190 arglist[pos].doubleValue = va_arg(ap, double);
michael@0 1191 break;
michael@0 1192 default:
michael@0 1193 /* else args is ignored */
michael@0 1194 arglist[pos].ptrValue = NULL;
michael@0 1195 break;
michael@0 1196 }
michael@0 1197 }
michael@0 1198
michael@0 1199 uprv_free(typelist);
michael@0 1200 uprv_free(islonglong);
michael@0 1201
michael@0 1202 return arglist;
michael@0 1203 }
michael@0 1204
michael@0 1205 /* We parse the argument list in Unicode */
michael@0 1206 U_CFUNC int32_t
michael@0 1207 u_printf_parse(const u_printf_stream_handler *streamHandler,
michael@0 1208 const UChar *fmt,
michael@0 1209 void *context,
michael@0 1210 u_localized_print_string *locStringContext,
michael@0 1211 ULocaleBundle *formatBundle,
michael@0 1212 int32_t *written,
michael@0 1213 va_list ap)
michael@0 1214 {
michael@0 1215 uint16_t handlerNum;
michael@0 1216 ufmt_args args;
michael@0 1217 ufmt_type_info argType;
michael@0 1218 u_printf_handler *handler;
michael@0 1219 u_printf_spec spec;
michael@0 1220 u_printf_spec_info *info = &(spec.fInfo);
michael@0 1221
michael@0 1222 const UChar *alias = fmt;
michael@0 1223 const UChar *backup;
michael@0 1224 const UChar *lastAlias;
michael@0 1225 const UChar *orgAlias = fmt;
michael@0 1226 /* parsed argument list */
michael@0 1227 ufmt_args *arglist = NULL; /* initialized it to avoid compiler warnings */
michael@0 1228 UErrorCode status = U_ZERO_ERROR;
michael@0 1229 if (!locStringContext || locStringContext->available >= 0) {
michael@0 1230 /* get the parsed list of argument types */
michael@0 1231 arglist = parseArguments(orgAlias, ap, &status);
michael@0 1232
michael@0 1233 /* Return error if parsing failed. */
michael@0 1234 if (U_FAILURE(status)) {
michael@0 1235 return -1;
michael@0 1236 }
michael@0 1237 }
michael@0 1238
michael@0 1239 /* iterate through the pattern */
michael@0 1240 while(!locStringContext || locStringContext->available >= 0) {
michael@0 1241
michael@0 1242 /* find the next '%' */
michael@0 1243 lastAlias = alias;
michael@0 1244 while(*alias != UP_PERCENT && *alias != 0x0000) {
michael@0 1245 alias++;
michael@0 1246 }
michael@0 1247
michael@0 1248 /* write any characters before the '%' */
michael@0 1249 if(alias > lastAlias) {
michael@0 1250 *written += (streamHandler->write)(context, lastAlias, (int32_t)(alias - lastAlias));
michael@0 1251 }
michael@0 1252
michael@0 1253 /* break if at end of string */
michael@0 1254 if(*alias == 0x0000) {
michael@0 1255 break;
michael@0 1256 }
michael@0 1257
michael@0 1258 /* initialize spec to default values */
michael@0 1259 spec.fWidthPos = -1;
michael@0 1260 spec.fPrecisionPos = -1;
michael@0 1261 spec.fArgPos = -1;
michael@0 1262
michael@0 1263 uprv_memset(info, 0, sizeof(*info));
michael@0 1264 info->fPrecision = -1;
michael@0 1265 info->fWidth = -1;
michael@0 1266 info->fPadChar = 0x0020;
michael@0 1267
michael@0 1268 /* skip over the initial '%' */
michael@0 1269 alias++;
michael@0 1270
michael@0 1271 /* Check for positional argument */
michael@0 1272 if(ISDIGIT(*alias)) {
michael@0 1273
michael@0 1274 /* Save the current position */
michael@0 1275 backup = alias;
michael@0 1276
michael@0 1277 /* handle positional parameters */
michael@0 1278 if(ISDIGIT(*alias)) {
michael@0 1279 spec.fArgPos = (int) (*alias++ - DIGIT_ZERO);
michael@0 1280
michael@0 1281 while(ISDIGIT(*alias)) {
michael@0 1282 spec.fArgPos *= 10;
michael@0 1283 spec.fArgPos += (int) (*alias++ - DIGIT_ZERO);
michael@0 1284 }
michael@0 1285 }
michael@0 1286
michael@0 1287 /* if there is no '$', don't read anything */
michael@0 1288 if(*alias != SPEC_DOLLARSIGN) {
michael@0 1289 spec.fArgPos = -1;
michael@0 1290 alias = backup;
michael@0 1291 }
michael@0 1292 /* munge the '$' */
michael@0 1293 else
michael@0 1294 alias++;
michael@0 1295 }
michael@0 1296
michael@0 1297 /* Get any format flags */
michael@0 1298 while(ISFLAG(*alias)) {
michael@0 1299 switch(*alias++) {
michael@0 1300
michael@0 1301 /* left justify */
michael@0 1302 case FLAG_MINUS:
michael@0 1303 info->fLeft = TRUE;
michael@0 1304 break;
michael@0 1305
michael@0 1306 /* always show sign */
michael@0 1307 case FLAG_PLUS:
michael@0 1308 info->fShowSign = TRUE;
michael@0 1309 break;
michael@0 1310
michael@0 1311 /* use space if no sign present */
michael@0 1312 case FLAG_SPACE:
michael@0 1313 info->fShowSign = TRUE;
michael@0 1314 info->fSpace = TRUE;
michael@0 1315 break;
michael@0 1316
michael@0 1317 /* use alternate form */
michael@0 1318 case FLAG_POUND:
michael@0 1319 info->fAlt = TRUE;
michael@0 1320 break;
michael@0 1321
michael@0 1322 /* pad with leading zeroes */
michael@0 1323 case FLAG_ZERO:
michael@0 1324 info->fZero = TRUE;
michael@0 1325 info->fPadChar = 0x0030;
michael@0 1326 break;
michael@0 1327
michael@0 1328 /* pad character specified */
michael@0 1329 case FLAG_PAREN:
michael@0 1330
michael@0 1331 /* TODO test that all four are numbers */
michael@0 1332 /* first four characters are hex values for pad char */
michael@0 1333 info->fPadChar = (UChar)ufmt_digitvalue(*alias++);
michael@0 1334 info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
michael@0 1335 info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
michael@0 1336 info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
michael@0 1337
michael@0 1338 /* final character is ignored */
michael@0 1339 alias++;
michael@0 1340
michael@0 1341 break;
michael@0 1342 }
michael@0 1343 }
michael@0 1344
michael@0 1345 /* Get the width */
michael@0 1346
michael@0 1347 /* width is specified out of line */
michael@0 1348 if(*alias == SPEC_ASTERISK) {
michael@0 1349
michael@0 1350 info->fWidth = -2;
michael@0 1351
michael@0 1352 /* Skip the '*' */
michael@0 1353 alias++;
michael@0 1354
michael@0 1355 /* Save the current position */
michael@0 1356 backup = alias;
michael@0 1357
michael@0 1358 /* handle positional parameters */
michael@0 1359 if(ISDIGIT(*alias)) {
michael@0 1360 spec.fWidthPos = (int) (*alias++ - DIGIT_ZERO);
michael@0 1361
michael@0 1362 while(ISDIGIT(*alias)) {
michael@0 1363 spec.fWidthPos *= 10;
michael@0 1364 spec.fWidthPos += (int) (*alias++ - DIGIT_ZERO);
michael@0 1365 }
michael@0 1366 }
michael@0 1367
michael@0 1368 /* if there is no '$', don't read anything */
michael@0 1369 if(*alias != SPEC_DOLLARSIGN) {
michael@0 1370 spec.fWidthPos = -1;
michael@0 1371 alias = backup;
michael@0 1372 }
michael@0 1373 /* munge the '$' */
michael@0 1374 else
michael@0 1375 alias++;
michael@0 1376 }
michael@0 1377 /* read the width, if present */
michael@0 1378 else if(ISDIGIT(*alias)){
michael@0 1379 info->fWidth = (int) (*alias++ - DIGIT_ZERO);
michael@0 1380
michael@0 1381 while(ISDIGIT(*alias)) {
michael@0 1382 info->fWidth *= 10;
michael@0 1383 info->fWidth += (int) (*alias++ - DIGIT_ZERO);
michael@0 1384 }
michael@0 1385 }
michael@0 1386
michael@0 1387 /* Get the precision */
michael@0 1388
michael@0 1389 if(*alias == SPEC_PERIOD) {
michael@0 1390
michael@0 1391 /* eat up the '.' */
michael@0 1392 alias++;
michael@0 1393
michael@0 1394 /* precision is specified out of line */
michael@0 1395 if(*alias == SPEC_ASTERISK) {
michael@0 1396
michael@0 1397 info->fPrecision = -2;
michael@0 1398
michael@0 1399 /* Skip the '*' */
michael@0 1400 alias++;
michael@0 1401
michael@0 1402 /* save the current position */
michael@0 1403 backup = alias;
michael@0 1404
michael@0 1405 /* handle positional parameters */
michael@0 1406 if(ISDIGIT(*alias)) {
michael@0 1407 spec.fPrecisionPos = (int) (*alias++ - DIGIT_ZERO);
michael@0 1408
michael@0 1409 while(ISDIGIT(*alias)) {
michael@0 1410 spec.fPrecisionPos *= 10;
michael@0 1411 spec.fPrecisionPos += (int) (*alias++ - DIGIT_ZERO);
michael@0 1412 }
michael@0 1413
michael@0 1414 /* if there is no '$', don't read anything */
michael@0 1415 if(*alias != SPEC_DOLLARSIGN) {
michael@0 1416 spec.fPrecisionPos = -1;
michael@0 1417 alias = backup;
michael@0 1418 }
michael@0 1419 else {
michael@0 1420 /* munge the '$' */
michael@0 1421 alias++;
michael@0 1422 }
michael@0 1423 }
michael@0 1424 }
michael@0 1425 /* read the precision */
michael@0 1426 else if(ISDIGIT(*alias)){
michael@0 1427 info->fPrecision = (int) (*alias++ - DIGIT_ZERO);
michael@0 1428
michael@0 1429 while(ISDIGIT(*alias)) {
michael@0 1430 info->fPrecision *= 10;
michael@0 1431 info->fPrecision += (int) (*alias++ - DIGIT_ZERO);
michael@0 1432 }
michael@0 1433 }
michael@0 1434 }
michael@0 1435
michael@0 1436 /* Get any modifiers */
michael@0 1437 if(ISMOD(*alias)) {
michael@0 1438 switch(*alias++) {
michael@0 1439
michael@0 1440 /* short */
michael@0 1441 case MOD_H:
michael@0 1442 info->fIsShort = TRUE;
michael@0 1443 break;
michael@0 1444
michael@0 1445 /* long or long long */
michael@0 1446 case MOD_LOWERL:
michael@0 1447 if(*alias == MOD_LOWERL) {
michael@0 1448 info->fIsLongLong = TRUE;
michael@0 1449 /* skip over the next 'l' */
michael@0 1450 alias++;
michael@0 1451 }
michael@0 1452 else
michael@0 1453 info->fIsLong = TRUE;
michael@0 1454 break;
michael@0 1455
michael@0 1456 /* long double */
michael@0 1457 case MOD_L:
michael@0 1458 info->fIsLongDouble = TRUE;
michael@0 1459 break;
michael@0 1460 }
michael@0 1461 }
michael@0 1462
michael@0 1463 /* finally, get the specifier letter */
michael@0 1464 info->fSpec = *alias++;
michael@0 1465 info->fOrigSpec = info->fSpec;
michael@0 1466
michael@0 1467 /* fill in the precision and width, if specified out of line */
michael@0 1468
michael@0 1469 /* width specified out of line */
michael@0 1470 if(spec.fInfo.fWidth == -2) {
michael@0 1471 if(spec.fWidthPos == -1) {
michael@0 1472 /* read the width from the argument list */
michael@0 1473 info->fWidth = va_arg(ap, int32_t);
michael@0 1474 }
michael@0 1475 /* else handle positional parameter */
michael@0 1476
michael@0 1477 /* if it's negative, take the absolute value and set left alignment */
michael@0 1478 if(info->fWidth < 0) {
michael@0 1479 info->fWidth *= -1; /* Make positive */
michael@0 1480 info->fLeft = TRUE;
michael@0 1481 }
michael@0 1482 }
michael@0 1483
michael@0 1484 /* precision specified out of line */
michael@0 1485 if(info->fPrecision == -2) {
michael@0 1486 if(spec.fPrecisionPos == -1) {
michael@0 1487 /* read the precision from the argument list */
michael@0 1488 info->fPrecision = va_arg(ap, int32_t);
michael@0 1489 }
michael@0 1490 /* else handle positional parameter */
michael@0 1491
michael@0 1492 /* if it's negative, set it to zero */
michael@0 1493 if(info->fPrecision < 0)
michael@0 1494 info->fPrecision = 0;
michael@0 1495 }
michael@0 1496
michael@0 1497 handlerNum = (uint16_t)(info->fSpec - UPRINTF_BASE_FMT_HANDLERS);
michael@0 1498 if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) {
michael@0 1499 /* query the info function for argument information */
michael@0 1500 argType = g_u_printf_infos[ handlerNum ].info;
michael@0 1501
michael@0 1502 /* goto the correct argument on arg_list if position is specified */
michael@0 1503 if (spec.fArgPos > 0) {
michael@0 1504 /* offset position by 1 */
michael@0 1505 spec.fArgPos--;
michael@0 1506 switch(argType) {
michael@0 1507 case ufmt_count:
michael@0 1508 /* set the spec's width to the # of chars written */
michael@0 1509 info->fWidth = *written;
michael@0 1510 /* fall through to set the pointer */
michael@0 1511 case ufmt_string:
michael@0 1512 case ufmt_ustring:
michael@0 1513 case ufmt_pointer:
michael@0 1514 args.ptrValue = arglist[spec.fArgPos].ptrValue;
michael@0 1515 break;
michael@0 1516 case ufmt_char:
michael@0 1517 case ufmt_uchar:
michael@0 1518 case ufmt_int:
michael@0 1519 args.int64Value = arglist[spec.fArgPos].int64Value;
michael@0 1520 break;
michael@0 1521 case ufmt_float:
michael@0 1522 args.floatValue = arglist[spec.fArgPos].floatValue;
michael@0 1523 break;
michael@0 1524 case ufmt_double:
michael@0 1525 args.doubleValue = arglist[spec.fArgPos].doubleValue;
michael@0 1526 break;
michael@0 1527 default:
michael@0 1528 /* else args is ignored */
michael@0 1529 args.ptrValue = NULL;
michael@0 1530 break;
michael@0 1531 }
michael@0 1532 } else { /* no positional argument specified */
michael@0 1533 switch(argType) {
michael@0 1534 case ufmt_count:
michael@0 1535 /* set the spec's width to the # of chars written */
michael@0 1536 info->fWidth = *written;
michael@0 1537 /* fall through to set the pointer */
michael@0 1538 case ufmt_string:
michael@0 1539 case ufmt_ustring:
michael@0 1540 case ufmt_pointer:
michael@0 1541 args.ptrValue = va_arg(ap, void*);
michael@0 1542 break;
michael@0 1543 case ufmt_char:
michael@0 1544 case ufmt_uchar:
michael@0 1545 case ufmt_int:
michael@0 1546 if (info->fIsLongLong) {
michael@0 1547 args.int64Value = va_arg(ap, int64_t);
michael@0 1548 }
michael@0 1549 else {
michael@0 1550 args.int64Value = va_arg(ap, int32_t);
michael@0 1551 }
michael@0 1552 break;
michael@0 1553 case ufmt_float:
michael@0 1554 args.floatValue = (float) va_arg(ap, double);
michael@0 1555 break;
michael@0 1556 case ufmt_double:
michael@0 1557 args.doubleValue = va_arg(ap, double);
michael@0 1558 break;
michael@0 1559 default:
michael@0 1560 /* else args is ignored */
michael@0 1561 args.ptrValue = NULL;
michael@0 1562 break;
michael@0 1563 }
michael@0 1564 }
michael@0 1565
michael@0 1566 /* call the handler function */
michael@0 1567 handler = g_u_printf_infos[ handlerNum ].handler;
michael@0 1568 if(handler != 0) {
michael@0 1569 *written += (*handler)(streamHandler, context, formatBundle, info, &args);
michael@0 1570 }
michael@0 1571 else {
michael@0 1572 /* just echo unknown tags */
michael@0 1573 *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias));
michael@0 1574 }
michael@0 1575 }
michael@0 1576 else {
michael@0 1577 /* just echo unknown tags */
michael@0 1578 *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias));
michael@0 1579 }
michael@0 1580 }
michael@0 1581 /* delete parsed argument list */
michael@0 1582 if (arglist != NULL) {
michael@0 1583 uprv_free(arglist);
michael@0 1584 }
michael@0 1585 /* return # of characters in this format that have been parsed. */
michael@0 1586 return (int32_t)(alias - fmt);
michael@0 1587 }
michael@0 1588
michael@0 1589 #endif /* #if !UCONFIG_NO_FORMATTING */

mercurial