uprntf_p.c revision 51cfa1a9a96cad34675a6415fe86dfdf3f525bb6
1/* 2****************************************************************************** 3* 4* Copyright (C) 1998-2006, 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 */ 84typedef int32_t U_EXPORT2 85u_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 92typedef 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 */ 100typedef 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 116static const UChar gNullStr[] = {0x28, 0x6E, 0x75, 0x6C, 0x6C, 0x29, 0}; /* "(null)" */ 117static 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? */ 121static void 122u_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 160static void 161u_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 '%' */ 178static int32_t 179u_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' */ 192static int32_t 193u_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 242static int32_t 243u_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 270static int32_t 271u_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 */ 346static int32_t 347u_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 412static int32_t 413u_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 447static int32_t 448u_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 481static int32_t 482u_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 534static int32_t 535u_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 550static int32_t 551u_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 670static int32_t 671u_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 745static int32_t 746u_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 773static int32_t 774u_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 793static int32_t 794u_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 804 memcpy(&scidbl_info, info, sizeof(u_printf_spec_info)); 805 806 /* determine whether to use 'd', 'e' or 'f' notation */ 807 if (scidbl_info.fPrecision == -1 && num == uprv_trunc(num)) 808 { 809 /* use 'f' notation */ 810 scidbl_info.fSpec = 0x0066; 811 scidbl_info.fPrecision = 0; 812 /* call the double handler */ 813 retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args); 814 } 815 else if(num < 0.0001 || (scidbl_info.fPrecision < 1 && 1000000.0 <= num) 816 || (scidbl_info.fPrecision != -1 && num > uprv_pow10(scidbl_info.fPrecision))) 817 { 818 /* use 'e' or 'E' notation */ 819 scidbl_info.fSpec = scidbl_info.fSpec - 2; 820 if (scidbl_info.fPrecision == -1) { 821 scidbl_info.fPrecision = 5; 822 } 823 /* call the scientific handler */ 824 retVal = u_printf_scientific_handler(handler, context, formatBundle, &scidbl_info, args); 825 } 826 else { 827 UNumberFormat *format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL); 828 int32_t maxSigDecimalDigits = unum_getAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS); 829 int32_t significantDigits = scidbl_info.fPrecision; 830 831 /* use 'f' notation */ 832 scidbl_info.fSpec = 0x0066; 833 if (significantDigits == -1) { 834 significantDigits = 6; 835 } 836 unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, TRUE); 837 unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, significantDigits); 838 /* call the double handler */ 839 retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args); 840 unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, maxSigDecimalDigits); 841 unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, FALSE); 842 } 843 return retVal; 844} 845 846static int32_t 847u_printf_count_handler(const u_printf_stream_handler *handler, 848 void *context, 849 ULocaleBundle *formatBundle, 850 const u_printf_spec_info *info, 851 const ufmt_args *args) 852{ 853 int32_t *count = (int32_t*)(args[0].ptrValue); 854 855 /* in the special case of count, the u_printf_spec_info's width */ 856 /* will contain the # of chars written thus far */ 857 *count = info->fWidth; 858 859 return 0; 860} 861 862static int32_t 863u_printf_spellout_handler(const u_printf_stream_handler *handler, 864 void *context, 865 ULocaleBundle *formatBundle, 866 const u_printf_spec_info *info, 867 const ufmt_args *args) 868{ 869 double num = (double) (args[0].doubleValue); 870 UNumberFormat *format; 871 UChar result[UPRINTF_BUFFER_SIZE]; 872 UChar prefixBuffer[UPRINTF_BUFFER_SIZE]; 873 int32_t prefixBufferLen = sizeof(prefixBuffer); 874 int32_t minDecimalDigits; 875 int32_t maxDecimalDigits; 876 int32_t resultLen; 877 UErrorCode status = U_ZERO_ERROR; 878 879 prefixBuffer[0] = 0; 880 881 /* mask off any necessary bits */ 882 /* if(! info->fIsLongDouble) 883 num &= DBL_MAX;*/ 884 885 /* get the formatter */ 886 format = u_locbund_getNumberFormat(formatBundle, UNUM_SPELLOUT); 887 888 /* handle error */ 889 if(format == 0) 890 return 0; 891 892 /* save the formatter's state */ 893 minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS); 894 maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS); 895 896 /* set the appropriate flags and number of decimal digits on the formatter */ 897 if(info->fPrecision != -1) { 898 /* set the # of decimal digits */ 899 unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision); 900 } 901 else if(info->fAlt) { 902 /* '#' means always show decimal point */ 903 /* copy of printf behavior on Solaris - '#' shows 6 digits */ 904 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); 905 } 906 else { 907 /* # of decimal digits is 6 if precision not specified */ 908 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); 909 } 910 911 /* set whether to show the sign */ 912 if (info->fShowSign) { 913 u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status); 914 } 915 916 /* format the number */ 917 resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status); 918 919 if (U_FAILURE(status)) { 920 resultLen = 0; 921 } 922 923 /* restore the number format */ 924 /* TODO: Is this needed? */ 925 unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits); 926 unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits); 927 928 if (info->fShowSign) { 929 /* Reset back to original value regardless of what the error was */ 930 UErrorCode localStatus = U_ZERO_ERROR; 931 u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus); 932 } 933 934 return handler->pad_and_justify(context, info, result, resultLen); 935} 936 937/* Use US-ASCII characters only for formatting. Most codepages have 938 characters 20-7F from Unicode. Using any other codepage specific 939 characters will make it very difficult to format the string on 940 non-Unicode machines */ 941static const u_printf_info g_u_printf_infos[UPRINTF_NUM_FMT_HANDLERS] = { 942/* 0x20 */ 943 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 944 UFMT_EMPTY, UFMT_SIMPLE_PERCENT,UFMT_EMPTY, UFMT_EMPTY, 945 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 946 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 947 948/* 0x30 */ 949 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 950 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 951 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 952 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 953 954/* 0x40 */ 955 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_UCHAR, 956 UFMT_EMPTY, UFMT_SCIENTIFIC, UFMT_EMPTY, UFMT_SCIDBL, 957#ifdef U_USE_OBSOLETE_IO_FORMATTING 958 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_UCHAR/*deprecated*/, 959#else 960 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 961#endif 962 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 963 964/* 0x50 */ 965 UFMT_PERCENT, UFMT_EMPTY, UFMT_EMPTY, UFMT_USTRING, 966#ifdef U_USE_OBSOLETE_IO_FORMATTING 967 UFMT_EMPTY, UFMT_USTRING/*deprecated*/,UFMT_SPELLOUT, UFMT_EMPTY, 968#else 969 UFMT_EMPTY, UFMT_EMPTY, UFMT_SPELLOUT, UFMT_EMPTY, 970#endif 971 UFMT_HEX, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 972 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 973 974/* 0x60 */ 975 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_CHAR, 976 UFMT_INT, UFMT_SCIENTIFIC, UFMT_DOUBLE, UFMT_SCIDBL, 977 UFMT_EMPTY, UFMT_INT, UFMT_EMPTY, UFMT_EMPTY, 978 UFMT_EMPTY, UFMT_EMPTY, UFMT_COUNT, UFMT_OCTAL, 979 980/* 0x70 */ 981 UFMT_POINTER, UFMT_EMPTY, UFMT_EMPTY, UFMT_STRING, 982 UFMT_EMPTY, UFMT_UINT, UFMT_EMPTY, UFMT_EMPTY, 983 UFMT_HEX, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 984 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 985}; 986 987/* flag characters for uprintf */ 988#define FLAG_MINUS 0x002D 989#define FLAG_PLUS 0x002B 990#define FLAG_SPACE 0x0020 991#define FLAG_POUND 0x0023 992#define FLAG_ZERO 0x0030 993#define FLAG_PAREN 0x0028 994 995#define ISFLAG(s) (s) == FLAG_MINUS || \ 996 (s) == FLAG_PLUS || \ 997 (s) == FLAG_SPACE || \ 998 (s) == FLAG_POUND || \ 999 (s) == FLAG_ZERO || \ 1000 (s) == FLAG_PAREN 1001 1002/* special characters for uprintf */ 1003#define SPEC_ASTERISK 0x002A 1004#define SPEC_DOLLARSIGN 0x0024 1005#define SPEC_PERIOD 0x002E 1006#define SPEC_PERCENT 0x0025 1007 1008/* unicode digits */ 1009#define DIGIT_ZERO 0x0030 1010#define DIGIT_ONE 0x0031 1011#define DIGIT_TWO 0x0032 1012#define DIGIT_THREE 0x0033 1013#define DIGIT_FOUR 0x0034 1014#define DIGIT_FIVE 0x0035 1015#define DIGIT_SIX 0x0036 1016#define DIGIT_SEVEN 0x0037 1017#define DIGIT_EIGHT 0x0038 1018#define DIGIT_NINE 0x0039 1019 1020#define ISDIGIT(s) (s) == DIGIT_ZERO || \ 1021 (s) == DIGIT_ONE || \ 1022 (s) == DIGIT_TWO || \ 1023 (s) == DIGIT_THREE || \ 1024 (s) == DIGIT_FOUR || \ 1025 (s) == DIGIT_FIVE || \ 1026 (s) == DIGIT_SIX || \ 1027 (s) == DIGIT_SEVEN || \ 1028 (s) == DIGIT_EIGHT || \ 1029 (s) == DIGIT_NINE 1030 1031/* u_printf modifiers */ 1032#define MOD_H 0x0068 1033#define MOD_LOWERL 0x006C 1034#define MOD_L 0x004C 1035 1036#define ISMOD(s) (s) == MOD_H || \ 1037 (s) == MOD_LOWERL || \ 1038 (s) == MOD_L 1039 1040/* We parse the argument list in Unicode */ 1041U_CFUNC int32_t 1042u_printf_parse(const u_printf_stream_handler *streamHandler, 1043 const UChar *fmt, 1044 void *context, 1045 u_localized_print_string *locStringContext, 1046 ULocaleBundle *formatBundle, 1047 int32_t *written, 1048 va_list ap) 1049{ 1050 uint16_t handlerNum; 1051 ufmt_args args; 1052 ufmt_type_info argType; 1053 u_printf_handler *handler; 1054 u_printf_spec spec; 1055 u_printf_spec_info *info = &(spec.fInfo); 1056 1057 const UChar *alias = fmt; 1058 const UChar *backup; 1059 const UChar *lastAlias; 1060 1061 /* iterate through the pattern */ 1062 while(!locStringContext || locStringContext->available > 0) { 1063 1064 /* find the next '%' */ 1065 lastAlias = alias; 1066 while(*alias != UP_PERCENT && *alias != 0x0000) { 1067 alias++; 1068 } 1069 1070 /* write any characters before the '%' */ 1071 if(alias > lastAlias) { 1072 *written += (streamHandler->write)(context, lastAlias, (int32_t)(alias - lastAlias)); 1073 } 1074 1075 /* break if at end of string */ 1076 if(*alias == 0x0000) { 1077 break; 1078 } 1079 1080 /* initialize spec to default values */ 1081 spec.fWidthPos = -1; 1082 spec.fPrecisionPos = -1; 1083 spec.fArgPos = -1; 1084 1085 uprv_memset(info, 0, sizeof(*info)); 1086 info->fPrecision = -1; 1087 info->fWidth = -1; 1088 info->fPadChar = 0x0020; 1089 1090 /* skip over the initial '%' */ 1091 alias++; 1092 1093 /* Check for positional argument */ 1094 if(ISDIGIT(*alias)) { 1095 1096 /* Save the current position */ 1097 backup = alias; 1098 1099 /* handle positional parameters */ 1100 if(ISDIGIT(*alias)) { 1101 spec.fArgPos = (int) (*alias++ - DIGIT_ZERO); 1102 1103 while(ISDIGIT(*alias)) { 1104 spec.fArgPos *= 10; 1105 spec.fArgPos += (int) (*alias++ - DIGIT_ZERO); 1106 } 1107 } 1108 1109 /* if there is no '$', don't read anything */ 1110 if(*alias != SPEC_DOLLARSIGN) { 1111 spec.fArgPos = -1; 1112 alias = backup; 1113 } 1114 /* munge the '$' */ 1115 else 1116 alias++; 1117 } 1118 1119 /* Get any format flags */ 1120 while(ISFLAG(*alias)) { 1121 switch(*alias++) { 1122 1123 /* left justify */ 1124 case FLAG_MINUS: 1125 info->fLeft = TRUE; 1126 break; 1127 1128 /* always show sign */ 1129 case FLAG_PLUS: 1130 info->fShowSign = TRUE; 1131 break; 1132 1133 /* use space if no sign present */ 1134 case FLAG_SPACE: 1135 info->fShowSign = TRUE; 1136 info->fSpace = TRUE; 1137 break; 1138 1139 /* use alternate form */ 1140 case FLAG_POUND: 1141 info->fAlt = TRUE; 1142 break; 1143 1144 /* pad with leading zeroes */ 1145 case FLAG_ZERO: 1146 info->fZero = TRUE; 1147 info->fPadChar = 0x0030; 1148 break; 1149 1150 /* pad character specified */ 1151 case FLAG_PAREN: 1152 1153 /* TODO test that all four are numbers */ 1154 /* first four characters are hex values for pad char */ 1155 info->fPadChar = (UChar)ufmt_digitvalue(*alias++); 1156 info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++)); 1157 info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++)); 1158 info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++)); 1159 1160 /* final character is ignored */ 1161 alias++; 1162 1163 break; 1164 } 1165 } 1166 1167 /* Get the width */ 1168 1169 /* width is specified out of line */ 1170 if(*alias == SPEC_ASTERISK) { 1171 1172 info->fWidth = -2; 1173 1174 /* Skip the '*' */ 1175 alias++; 1176 1177 /* Save the current position */ 1178 backup = alias; 1179 1180 /* handle positional parameters */ 1181 if(ISDIGIT(*alias)) { 1182 spec.fWidthPos = (int) (*alias++ - DIGIT_ZERO); 1183 1184 while(ISDIGIT(*alias)) { 1185 spec.fWidthPos *= 10; 1186 spec.fWidthPos += (int) (*alias++ - DIGIT_ZERO); 1187 } 1188 } 1189 1190 /* if there is no '$', don't read anything */ 1191 if(*alias != SPEC_DOLLARSIGN) { 1192 spec.fWidthPos = -1; 1193 alias = backup; 1194 } 1195 /* munge the '$' */ 1196 else 1197 alias++; 1198 } 1199 /* read the width, if present */ 1200 else if(ISDIGIT(*alias)){ 1201 info->fWidth = (int) (*alias++ - DIGIT_ZERO); 1202 1203 while(ISDIGIT(*alias)) { 1204 info->fWidth *= 10; 1205 info->fWidth += (int) (*alias++ - DIGIT_ZERO); 1206 } 1207 } 1208 1209 /* Get the precision */ 1210 1211 if(*alias == SPEC_PERIOD) { 1212 1213 /* eat up the '.' */ 1214 alias++; 1215 1216 /* precision is specified out of line */ 1217 if(*alias == SPEC_ASTERISK) { 1218 1219 info->fPrecision = -2; 1220 1221 /* Skip the '*' */ 1222 alias++; 1223 1224 /* save the current position */ 1225 backup = alias; 1226 1227 /* handle positional parameters */ 1228 if(ISDIGIT(*alias)) { 1229 spec.fPrecisionPos = (int) (*alias++ - DIGIT_ZERO); 1230 1231 while(ISDIGIT(*alias)) { 1232 spec.fPrecisionPos *= 10; 1233 spec.fPrecisionPos += (int) (*alias++ - DIGIT_ZERO); 1234 } 1235 1236 /* if there is no '$', don't read anything */ 1237 if(*alias != SPEC_DOLLARSIGN) { 1238 spec.fPrecisionPos = -1; 1239 alias = backup; 1240 } 1241 else { 1242 /* munge the '$' */ 1243 alias++; 1244 } 1245 } 1246 } 1247 /* read the precision */ 1248 else if(ISDIGIT(*alias)){ 1249 info->fPrecision = (int) (*alias++ - DIGIT_ZERO); 1250 1251 while(ISDIGIT(*alias)) { 1252 info->fPrecision *= 10; 1253 info->fPrecision += (int) (*alias++ - DIGIT_ZERO); 1254 } 1255 } 1256 } 1257 1258 /* Get any modifiers */ 1259 if(ISMOD(*alias)) { 1260 switch(*alias++) { 1261 1262 /* short */ 1263 case MOD_H: 1264 info->fIsShort = TRUE; 1265 break; 1266 1267 /* long or long long */ 1268 case MOD_LOWERL: 1269 if(*alias == MOD_LOWERL) { 1270 info->fIsLongLong = TRUE; 1271 /* skip over the next 'l' */ 1272 alias++; 1273 } 1274 else 1275 info->fIsLong = TRUE; 1276 break; 1277 1278 /* long double */ 1279 case MOD_L: 1280 info->fIsLongDouble = TRUE; 1281 break; 1282 } 1283 } 1284 1285 /* finally, get the specifier letter */ 1286 info->fSpec = *alias++; 1287 info->fOrigSpec = info->fSpec; 1288 1289 /* fill in the precision and width, if specified out of line */ 1290 1291 /* width specified out of line */ 1292 if(spec.fInfo.fWidth == -2) { 1293 if(spec.fWidthPos == -1) { 1294 /* read the width from the argument list */ 1295 info->fWidth = va_arg(ap, int32_t); 1296 } 1297 /* else handle positional parameter */ 1298 1299 /* if it's negative, take the absolute value and set left alignment */ 1300 if(info->fWidth < 0) { 1301 info->fWidth *= -1; /* Make positive */ 1302 info->fLeft = TRUE; 1303 } 1304 } 1305 1306 /* precision specified out of line */ 1307 if(info->fPrecision == -2) { 1308 if(spec.fPrecisionPos == -1) { 1309 /* read the precision from the argument list */ 1310 info->fPrecision = va_arg(ap, int32_t); 1311 } 1312 /* else handle positional parameter */ 1313 1314 /* if it's negative, set it to zero */ 1315 if(info->fPrecision < 0) 1316 info->fPrecision = 0; 1317 } 1318 1319 handlerNum = (uint16_t)(info->fSpec - UPRINTF_BASE_FMT_HANDLERS); 1320 if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) { 1321 /* query the info function for argument information */ 1322 argType = g_u_printf_infos[ handlerNum ].info; 1323 switch(argType) { 1324 case ufmt_count: 1325 /* set the spec's width to the # of chars written */ 1326 info->fWidth = *written; 1327 /* fall through to set the pointer */ 1328 case ufmt_string: 1329 case ufmt_ustring: 1330 case ufmt_pointer: 1331 args.ptrValue = va_arg(ap, void*); 1332 break; 1333 case ufmt_char: 1334 case ufmt_uchar: 1335 case ufmt_int: 1336 if (info->fIsLongLong) { 1337 args.int64Value = va_arg(ap, int64_t); 1338 } 1339 else { 1340 args.int64Value = va_arg(ap, int32_t); 1341 } 1342 break; 1343 case ufmt_float: 1344 args.floatValue = (float) va_arg(ap, double); 1345 break; 1346 case ufmt_double: 1347 args.doubleValue = va_arg(ap, double); 1348 break; 1349 default: 1350 /* else args is ignored */ 1351 args.ptrValue = NULL; 1352 break; 1353 } 1354 1355 /* call the handler function */ 1356 handler = g_u_printf_infos[ handlerNum ].handler; 1357 if(handler != 0) { 1358 *written += (*handler)(streamHandler, context, formatBundle, info, &args); 1359 } 1360 else { 1361 /* just echo unknown tags */ 1362 *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias)); 1363 } 1364 } 1365 else { 1366 /* just echo unknown tags */ 1367 *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias)); 1368 } 1369 } 1370 /* return # of characters in this format that have been parsed. */ 1371 return (int32_t)(alias - fmt); 1372} 1373 1374#endif /* #if !UCONFIG_NO_FORMATTING */ 1375