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