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