uprntf_p.cpp (54019B)
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, nullptr} 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 char16_t gNullStr[] = {0x28, 0x6E, 0x75, 0x6C, 0x6C, 0x29, 0}; /* "(null)" */ 119 static const char16_t 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 char16_t *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 char16_t 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 char16_t *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 char16_t 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 char16_t *s; 206 char16_t buffer[UFMT_DEFAULT_BUFFER_SIZE]; 207 int32_t len, written; 208 int32_t argSize; 209 const char* arg = static_cast<const char*>(args[0].ptrValue); 210 211 /* convert from the default codepage to Unicode */ 212 if (arg) { 213 argSize = static_cast<int32_t>(strlen(arg)) + 1; 214 if (argSize >= MAX_UCHAR_BUFFER_SIZE(buffer)) { 215 s = ufmt_defaultCPToUnicode(arg, argSize, 216 static_cast<char16_t*>(uprv_malloc(MAX_UCHAR_BUFFER_NEEDED(argSize))), 217 MAX_UCHAR_BUFFER_NEEDED(argSize)); 218 if(s == nullptr) { 219 return 0; 220 } 221 } 222 else { 223 s = ufmt_defaultCPToUnicode(arg, argSize, buffer, 224 UPRV_LENGTHOF(buffer)); 225 } 226 } 227 else { 228 s = (char16_t *)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 char16_t s[U16_MAX_LENGTH+1]; 257 int32_t len = 1, written; 258 unsigned char arg = static_cast<unsigned char>(args[0].int64Value); 259 260 /* convert from default codepage to Unicode */ 261 ufmt_defaultCPToUnicode(reinterpret_cast<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 = args[0].doubleValue; 285 UNumberFormat *format; 286 char16_t result[UPRINTF_BUFFER_SIZE]; 287 char16_t 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 == nullptr) 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, nullptr, &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 char16_t result[UPRINTF_BUFFER_SIZE]; 363 char16_t 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 = static_cast<int16_t>(num); 374 else if (!info->fIsLongLong) 375 num = static_cast<int32_t>(num); 376 377 /* get the formatter */ 378 format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL); 379 380 /* handle error */ 381 if (format == nullptr) 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, nullptr, &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 char16_t 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 static_cast<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(char16_t)); 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 char16_t 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(char16_t)); 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 char16_t 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 == nullptr) 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, nullptr, &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 char16_t 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 = args[0].doubleValue; 568 UNumberFormat *format; 569 char16_t result[UPRINTF_BUFFER_SIZE]; 570 char16_t 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 char16_t srcExpBuf[UPRINTF_SYMBOL_BUFFER_SIZE]; 576 int32_t srcLen, expLen; 577 int32_t resultLen; 578 char16_t 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 == nullptr) 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 == static_cast<char16_t>(0x65) /* e */) { 603 expLen = u_strToLower(expBuf, static_cast<int32_t>(sizeof(expBuf)), 604 srcExpBuf, srcLen, 605 formatBundle->fLocale, 606 &status); 607 } 608 else { 609 expLen = u_strToUpper(expBuf, static_cast<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 == static_cast<char16_t>(0x65) /* e */ || 629 info->fOrigSpec == static_cast<char16_t>(0x45) /* E */) { 630 unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision); 631 } 632 else { 633 unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, 1); 634 unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, info->fPrecision); 635 } 636 } 637 else if(info->fAlt) { 638 /* '#' means always show decimal point */ 639 /* copy of printf behavior on Solaris - '#' shows 6 digits */ 640 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); 641 } 642 else { 643 /* # of decimal digits is 6 if precision not specified */ 644 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); 645 } 646 647 /* set whether to show the sign */ 648 if (info->fShowSign) { 649 u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status); 650 } 651 652 /* format the number */ 653 resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, nullptr, &status); 654 655 if (U_FAILURE(status)) { 656 resultLen = 0; 657 } 658 659 /* restore the number format */ 660 /* TODO: Is this needed? */ 661 unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits); 662 unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits); 663 664 /* Since we're the only one using the scientific 665 format, we don't need to save the old exponent value. */ 666 /*unum_setSymbol(format, 667 UNUM_EXPONENTIAL_SYMBOL, 668 srcExpBuf, 669 srcLen, 670 &status);*/ 671 672 if (info->fShowSign) { 673 /* Reset back to original value regardless of what the error was */ 674 UErrorCode localStatus = U_ZERO_ERROR; 675 u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus); 676 } 677 678 return handler->pad_and_justify(context, info, result, resultLen); 679 } 680 681 static int32_t 682 u_printf_percent_handler(const u_printf_stream_handler *handler, 683 void *context, 684 ULocaleBundle *formatBundle, 685 const u_printf_spec_info *info, 686 const ufmt_args *args) 687 { 688 double num = args[0].doubleValue; 689 UNumberFormat *format; 690 char16_t result[UPRINTF_BUFFER_SIZE]; 691 char16_t prefixBuffer[UPRINTF_BUFFER_SIZE]; 692 int32_t prefixBufferLen = sizeof(prefixBuffer); 693 int32_t minDecimalDigits; 694 int32_t maxDecimalDigits; 695 int32_t resultLen; 696 UErrorCode status = U_ZERO_ERROR; 697 698 prefixBuffer[0] = 0; 699 700 /* mask off any necessary bits */ 701 /* if(! info->fIsLongDouble) 702 num &= DBL_MAX;*/ 703 704 /* get the formatter */ 705 format = u_locbund_getNumberFormat(formatBundle, UNUM_PERCENT); 706 707 /* handle error */ 708 if (format == nullptr) 709 return 0; 710 711 /* save the formatter's state */ 712 minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS); 713 maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS); 714 715 /* set the appropriate flags and number of decimal digits on the formatter */ 716 if(info->fPrecision != -1) { 717 /* set the # of decimal digits */ 718 unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision); 719 } 720 else if(info->fAlt) { 721 /* '#' means always show decimal point */ 722 /* copy of printf behavior on Solaris - '#' shows 6 digits */ 723 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); 724 } 725 else { 726 /* # of decimal digits is 6 if precision not specified */ 727 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); 728 } 729 730 /* set whether to show the sign */ 731 if (info->fShowSign) { 732 u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status); 733 } 734 735 /* format the number */ 736 resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, nullptr, &status); 737 738 if (U_FAILURE(status)) { 739 resultLen = 0; 740 } 741 742 /* restore the number format */ 743 /* TODO: Is this needed? */ 744 unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits); 745 unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits); 746 747 if (info->fShowSign) { 748 /* Reset back to original value regardless of what the error was */ 749 UErrorCode localStatus = U_ZERO_ERROR; 750 u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus); 751 } 752 753 return handler->pad_and_justify(context, info, result, resultLen); 754 } 755 756 static int32_t 757 u_printf_ustring_handler(const u_printf_stream_handler *handler, 758 void *context, 759 ULocaleBundle *formatBundle, 760 const u_printf_spec_info *info, 761 const ufmt_args *args) 762 { 763 (void)formatBundle; 764 int32_t len, written; 765 const char16_t* arg = static_cast<const char16_t*>(args[0].ptrValue); 766 767 /* allocate enough space for the buffer */ 768 if (arg == nullptr) { 769 arg = gNullStr; 770 } 771 len = u_strlen(arg); 772 773 /* width = minimum # of characters to write */ 774 /* precision = maximum # of characters to write */ 775 if (info->fPrecision != -1 && info->fPrecision < len) { 776 len = info->fPrecision; 777 } 778 779 /* determine if the string should be padded */ 780 written = handler->pad_and_justify(context, info, arg, len); 781 782 return written; 783 } 784 785 static int32_t 786 u_printf_uchar_handler(const u_printf_stream_handler *handler, 787 void *context, 788 ULocaleBundle *formatBundle, 789 const u_printf_spec_info *info, 790 const ufmt_args *args) 791 { 792 (void)formatBundle; 793 int32_t written = 0; 794 char16_t arg = static_cast<char16_t>(args[0].int64Value); 795 796 /* width = minimum # of characters to write */ 797 /* precision = maximum # of characters to write */ 798 /* precision is ignored when handling a uchar */ 799 800 /* determine if the string should be padded */ 801 written = handler->pad_and_justify(context, info, &arg, 1); 802 803 return written; 804 } 805 806 static int32_t 807 u_printf_scidbl_handler(const u_printf_stream_handler *handler, 808 void *context, 809 ULocaleBundle *formatBundle, 810 const u_printf_spec_info *info, 811 const ufmt_args *args) 812 { 813 u_printf_spec_info scidbl_info; 814 double num = args[0].doubleValue; 815 int32_t retVal; 816 UNumberFormat *format; 817 int32_t maxSigDecimalDigits, significantDigits; 818 819 memcpy(&scidbl_info, info, sizeof(u_printf_spec_info)); 820 821 /* determine whether to use 'd', 'e' or 'f' notation */ 822 if (scidbl_info.fPrecision == -1 && num == uprv_trunc(num)) 823 { 824 /* use 'f' notation */ 825 scidbl_info.fSpec = 0x0066; 826 scidbl_info.fPrecision = 0; 827 /* call the double handler */ 828 retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args); 829 } 830 else if(num < 0.0001 || (scidbl_info.fPrecision < 1 && 1000000.0 <= num) 831 || (scidbl_info.fPrecision != -1 && num > uprv_pow10(scidbl_info.fPrecision))) 832 { 833 /* use 'e' or 'E' notation */ 834 scidbl_info.fSpec = scidbl_info.fSpec - 2; 835 if (scidbl_info.fPrecision == -1) { 836 scidbl_info.fPrecision = 5; 837 } 838 /* call the scientific handler */ 839 retVal = u_printf_scientific_handler(handler, context, formatBundle, &scidbl_info, args); 840 } 841 else { 842 format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL); 843 /* Check for null pointer */ 844 if (format == nullptr) { 845 return 0; 846 } 847 maxSigDecimalDigits = unum_getAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS); 848 significantDigits = scidbl_info.fPrecision; 849 850 /* use 'f' notation */ 851 scidbl_info.fSpec = 0x0066; 852 if (significantDigits == -1) { 853 significantDigits = 6; 854 } 855 unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, true); 856 unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, significantDigits); 857 /* call the double handler */ 858 retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args); 859 unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, maxSigDecimalDigits); 860 unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, false); 861 } 862 return retVal; 863 } 864 865 static int32_t 866 u_printf_count_handler(const u_printf_stream_handler *handler, 867 void *context, 868 ULocaleBundle *formatBundle, 869 const u_printf_spec_info *info, 870 const ufmt_args *args) 871 { 872 (void)handler; 873 (void)context; 874 (void)formatBundle; 875 int32_t* count = static_cast<int32_t*>(args[0].ptrValue); 876 877 /* in the special case of count, the u_printf_spec_info's width */ 878 /* will contain the # of chars written thus far */ 879 *count = info->fWidth; 880 881 return 0; 882 } 883 884 static int32_t 885 u_printf_spellout_handler(const u_printf_stream_handler *handler, 886 void *context, 887 ULocaleBundle *formatBundle, 888 const u_printf_spec_info *info, 889 const ufmt_args *args) 890 { 891 double num = args[0].doubleValue; 892 UNumberFormat *format; 893 char16_t result[UPRINTF_BUFFER_SIZE]; 894 char16_t prefixBuffer[UPRINTF_BUFFER_SIZE]; 895 int32_t prefixBufferLen = sizeof(prefixBuffer); 896 int32_t minDecimalDigits; 897 int32_t maxDecimalDigits; 898 int32_t resultLen; 899 UErrorCode status = U_ZERO_ERROR; 900 901 prefixBuffer[0] = 0; 902 903 /* mask off any necessary bits */ 904 /* if(! info->fIsLongDouble) 905 num &= DBL_MAX;*/ 906 907 /* get the formatter */ 908 format = u_locbund_getNumberFormat(formatBundle, UNUM_SPELLOUT); 909 910 /* handle error */ 911 if (format == nullptr) 912 return 0; 913 914 /* save the formatter's state */ 915 minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS); 916 maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS); 917 918 /* set the appropriate flags and number of decimal digits on the formatter */ 919 if(info->fPrecision != -1) { 920 /* set the # of decimal digits */ 921 unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision); 922 } 923 else if(info->fAlt) { 924 /* '#' means always show decimal point */ 925 /* copy of printf behavior on Solaris - '#' shows 6 digits */ 926 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); 927 } 928 else { 929 /* # of decimal digits is 6 if precision not specified */ 930 unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6); 931 } 932 933 /* set whether to show the sign */ 934 if (info->fShowSign) { 935 u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status); 936 } 937 938 /* format the number */ 939 resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, nullptr, &status); 940 941 if (U_FAILURE(status)) { 942 resultLen = 0; 943 } 944 945 /* restore the number format */ 946 /* TODO: Is this needed? */ 947 unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits); 948 unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits); 949 950 if (info->fShowSign) { 951 /* Reset back to original value regardless of what the error was */ 952 UErrorCode localStatus = U_ZERO_ERROR; 953 u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus); 954 } 955 956 return handler->pad_and_justify(context, info, result, resultLen); 957 } 958 959 /* Use US-ASCII characters only for formatting. Most codepages have 960 characters 20-7F from Unicode. Using any other codepage specific 961 characters will make it very difficult to format the string on 962 non-Unicode machines */ 963 static const u_printf_info g_u_printf_infos[UPRINTF_NUM_FMT_HANDLERS] = { 964 /* 0x20 */ 965 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 966 UFMT_EMPTY, UFMT_SIMPLE_PERCENT,UFMT_EMPTY, UFMT_EMPTY, 967 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 968 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 969 970 /* 0x30 */ 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 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 975 976 /* 0x40 */ 977 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_UCHAR, 978 UFMT_EMPTY, UFMT_SCIENTIFIC, UFMT_EMPTY, UFMT_SCIDBL, 979 #ifdef U_USE_OBSOLETE_IO_FORMATTING 980 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_UCHAR/*deprecated*/, 981 #else 982 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 983 #endif 984 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 985 986 /* 0x50 */ 987 UFMT_PERCENT, UFMT_EMPTY, UFMT_EMPTY, UFMT_USTRING, 988 #ifdef U_USE_OBSOLETE_IO_FORMATTING 989 UFMT_EMPTY, UFMT_USTRING/*deprecated*/,UFMT_SPELLOUT, UFMT_EMPTY, 990 #else 991 UFMT_EMPTY, UFMT_EMPTY, UFMT_SPELLOUT, UFMT_EMPTY, 992 #endif 993 UFMT_HEX, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 994 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 995 996 /* 0x60 */ 997 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_CHAR, 998 UFMT_INT, UFMT_SCIENTIFIC, UFMT_DOUBLE, UFMT_SCIDBL, 999 UFMT_EMPTY, UFMT_INT, UFMT_EMPTY, UFMT_EMPTY, 1000 UFMT_EMPTY, UFMT_EMPTY, UFMT_COUNT, UFMT_OCTAL, 1001 1002 /* 0x70 */ 1003 UFMT_POINTER, UFMT_EMPTY, UFMT_EMPTY, UFMT_STRING, 1004 UFMT_EMPTY, UFMT_UINT, UFMT_EMPTY, UFMT_EMPTY, 1005 UFMT_HEX, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 1006 UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, UFMT_EMPTY, 1007 }; 1008 1009 /* flag characters for uprintf */ 1010 #define FLAG_MINUS 0x002D 1011 #define FLAG_PLUS 0x002B 1012 #define FLAG_SPACE 0x0020 1013 #define FLAG_POUND 0x0023 1014 #define FLAG_ZERO 0x0030 1015 #define FLAG_PAREN 0x0028 1016 1017 #define ISFLAG(s) (s) == FLAG_MINUS || \ 1018 (s) == FLAG_PLUS || \ 1019 (s) == FLAG_SPACE || \ 1020 (s) == FLAG_POUND || \ 1021 (s) == FLAG_ZERO || \ 1022 (s) == FLAG_PAREN 1023 1024 /* special characters for uprintf */ 1025 #define SPEC_ASTERISK 0x002A 1026 #define SPEC_DOLLARSIGN 0x0024 1027 #define SPEC_PERIOD 0x002E 1028 #define SPEC_PERCENT 0x0025 1029 1030 /* unicode digits */ 1031 #define DIGIT_ZERO 0x0030 1032 #define DIGIT_ONE 0x0031 1033 #define DIGIT_TWO 0x0032 1034 #define DIGIT_THREE 0x0033 1035 #define DIGIT_FOUR 0x0034 1036 #define DIGIT_FIVE 0x0035 1037 #define DIGIT_SIX 0x0036 1038 #define DIGIT_SEVEN 0x0037 1039 #define DIGIT_EIGHT 0x0038 1040 #define DIGIT_NINE 0x0039 1041 1042 #define ISDIGIT(s) (s) == DIGIT_ZERO || \ 1043 (s) == DIGIT_ONE || \ 1044 (s) == DIGIT_TWO || \ 1045 (s) == DIGIT_THREE || \ 1046 (s) == DIGIT_FOUR || \ 1047 (s) == DIGIT_FIVE || \ 1048 (s) == DIGIT_SIX || \ 1049 (s) == DIGIT_SEVEN || \ 1050 (s) == DIGIT_EIGHT || \ 1051 (s) == DIGIT_NINE 1052 1053 /* u_printf modifiers */ 1054 #define MOD_H 0x0068 1055 #define MOD_LOWERL 0x006C 1056 #define MOD_L 0x004C 1057 1058 #define ISMOD(s) (s) == MOD_H || \ 1059 (s) == MOD_LOWERL || \ 1060 (s) == MOD_L 1061 /* Returns an array of the parsed argument type given in the format string. */ 1062 static ufmt_args* parseArguments(const char16_t *alias, va_list ap, UErrorCode *status) { 1063 ufmt_args *arglist = nullptr; 1064 ufmt_type_info *typelist = nullptr; 1065 UBool *islonglong = nullptr; 1066 int32_t size = 0; 1067 int32_t pos = 0; 1068 char16_t type; 1069 uint16_t handlerNum; 1070 const char16_t *aliasStart = alias; 1071 1072 /* get maximum number of arguments */ 1073 for(;;) { 1074 /* find % */ 1075 while(*alias != UP_PERCENT && *alias != 0x0000) { 1076 alias++; 1077 } 1078 1079 if(*alias == 0x0000) { 1080 break; 1081 } 1082 1083 alias++; 1084 1085 /* handle the pos number */ 1086 if(ISDIGIT(*alias)) { 1087 1088 /* handle positional parameters */ 1089 if(ISDIGIT(*alias)) { 1090 pos = *alias++ - DIGIT_ZERO; 1091 1092 while(ISDIGIT(*alias)) { 1093 pos *= 10; 1094 pos += *alias++ - DIGIT_ZERO; 1095 } 1096 } 1097 1098 /* if there is no '$', don't read anything */ 1099 if(*alias != SPEC_DOLLARSIGN) { 1100 return nullptr; 1101 } 1102 } else { 1103 return nullptr; 1104 } 1105 1106 if (pos > size) { 1107 size = pos; 1108 } 1109 } 1110 1111 /* create the parsed argument list */ 1112 typelist = static_cast<ufmt_type_info*>(uprv_malloc(sizeof(ufmt_type_info) * size)); 1113 islonglong = static_cast<UBool*>(uprv_malloc(sizeof(UBool) * size)); 1114 arglist = static_cast<ufmt_args*>(uprv_malloc(sizeof(ufmt_args) * size)); 1115 1116 /* If malloc failed, return nullptr */ 1117 if (!typelist || !islonglong || !arglist) { 1118 if (typelist) { 1119 uprv_free(typelist); 1120 } 1121 1122 if (islonglong) { 1123 uprv_free(islonglong); 1124 } 1125 1126 if (arglist) { 1127 uprv_free(arglist); 1128 } 1129 1130 *status = U_MEMORY_ALLOCATION_ERROR; 1131 return nullptr; 1132 } 1133 1134 /* reset alias back to the beginning */ 1135 alias = aliasStart; 1136 1137 for(;;) { 1138 /* find % */ 1139 while(*alias != UP_PERCENT && *alias != 0x0000) { 1140 alias++; 1141 } 1142 1143 if(*alias == 0x0000) { 1144 break; 1145 } 1146 1147 alias++; 1148 1149 /* handle positional parameters */ 1150 if(ISDIGIT(*alias)) { 1151 pos = *alias++ - DIGIT_ZERO; 1152 1153 while(ISDIGIT(*alias)) { 1154 pos *= 10; 1155 pos += *alias++ - DIGIT_ZERO; 1156 } 1157 } 1158 /* offset position by 1 */ 1159 pos--; 1160 1161 /* skip over everything except for the type */ 1162 while (ISMOD(*alias) || ISFLAG(*alias) || ISDIGIT(*alias) || 1163 *alias == SPEC_ASTERISK || *alias == SPEC_PERIOD || *alias == SPEC_DOLLARSIGN) { 1164 islonglong[pos] = false; 1165 if (ISMOD(*alias)) { 1166 alias++; 1167 if (*alias == MOD_LOWERL) { 1168 islonglong[pos] = true; 1169 } 1170 } 1171 alias++; 1172 } 1173 type = *alias; 1174 1175 /* store the argument type in the correct position of the parsed argument list */ 1176 handlerNum = static_cast<uint16_t>(type - UPRINTF_BASE_FMT_HANDLERS); 1177 if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) { 1178 typelist[pos] = g_u_printf_infos[ handlerNum ].info; 1179 } else { 1180 typelist[pos] = ufmt_empty; 1181 } 1182 } 1183 1184 /* store argument in arglist */ 1185 for (pos = 0; pos < size; pos++) { 1186 switch (typelist[pos]) { 1187 case ufmt_string: 1188 case ufmt_ustring: 1189 case ufmt_pointer: 1190 arglist[pos].ptrValue = va_arg(ap, void*); 1191 break; 1192 case ufmt_char: 1193 case ufmt_uchar: 1194 case ufmt_int: 1195 if (islonglong[pos]) { 1196 arglist[pos].int64Value = va_arg(ap, int64_t); 1197 } 1198 else { 1199 arglist[pos].int64Value = va_arg(ap, int32_t); 1200 } 1201 break; 1202 case ufmt_float: 1203 arglist[pos].floatValue = static_cast<float>(va_arg(ap, double)); 1204 break; 1205 case ufmt_double: 1206 arglist[pos].doubleValue = va_arg(ap, double); 1207 break; 1208 default: 1209 /* else args is ignored */ 1210 arglist[pos].ptrValue = nullptr; 1211 break; 1212 } 1213 } 1214 1215 uprv_free(typelist); 1216 uprv_free(islonglong); 1217 1218 return arglist; 1219 } 1220 1221 /* We parse the argument list in Unicode */ 1222 U_CFUNC int32_t 1223 u_printf_parse(const u_printf_stream_handler *streamHandler, 1224 const char16_t *fmt, 1225 void *context, 1226 u_localized_print_string *locStringContext, 1227 ULocaleBundle *formatBundle, 1228 int32_t *written, 1229 va_list ap) 1230 { 1231 uint16_t handlerNum; 1232 ufmt_args args; 1233 ufmt_type_info argType; 1234 u_printf_handler *handler; 1235 u_printf_spec spec; 1236 u_printf_spec_info *info = &(spec.fInfo); 1237 1238 const char16_t *alias = fmt; 1239 const char16_t *backup; 1240 const char16_t *lastAlias; 1241 const char16_t *orgAlias = fmt; 1242 /* parsed argument list */ 1243 ufmt_args *arglist = nullptr; /* initialized it to avoid compiler warnings */ 1244 UErrorCode status = U_ZERO_ERROR; 1245 if (!locStringContext || locStringContext->available >= 0) { 1246 /* get the parsed list of argument types */ 1247 arglist = parseArguments(orgAlias, ap, &status); 1248 1249 /* Return error if parsing failed. */ 1250 if (U_FAILURE(status)) { 1251 return -1; 1252 } 1253 } 1254 1255 /* iterate through the pattern */ 1256 while(!locStringContext || locStringContext->available >= 0) { 1257 1258 /* find the next '%' */ 1259 lastAlias = alias; 1260 while(*alias != UP_PERCENT && *alias != 0x0000) { 1261 alias++; 1262 } 1263 1264 /* write any characters before the '%' */ 1265 if(alias > lastAlias) { 1266 *written += (streamHandler->write)(context, lastAlias, (int32_t)(alias - lastAlias)); 1267 } 1268 1269 /* break if at end of string */ 1270 if(*alias == 0x0000) { 1271 break; 1272 } 1273 1274 /* initialize spec to default values */ 1275 spec.fWidthPos = -1; 1276 spec.fPrecisionPos = -1; 1277 spec.fArgPos = -1; 1278 1279 uprv_memset(info, 0, sizeof(*info)); 1280 info->fPrecision = -1; 1281 info->fWidth = -1; 1282 info->fPadChar = 0x0020; 1283 1284 /* skip over the initial '%' */ 1285 alias++; 1286 1287 /* Check for positional argument */ 1288 if(ISDIGIT(*alias)) { 1289 1290 /* Save the current position */ 1291 backup = alias; 1292 1293 /* handle positional parameters */ 1294 if(ISDIGIT(*alias)) { 1295 spec.fArgPos = *alias++ - DIGIT_ZERO; 1296 1297 while(ISDIGIT(*alias)) { 1298 spec.fArgPos *= 10; 1299 spec.fArgPos += *alias++ - DIGIT_ZERO; 1300 } 1301 } 1302 1303 /* if there is no '$', don't read anything */ 1304 if(*alias != SPEC_DOLLARSIGN) { 1305 spec.fArgPos = -1; 1306 alias = backup; 1307 } 1308 /* munge the '$' */ 1309 else 1310 alias++; 1311 } 1312 1313 /* Get any format flags */ 1314 while(ISFLAG(*alias)) { 1315 switch(*alias++) { 1316 1317 /* left justify */ 1318 case FLAG_MINUS: 1319 info->fLeft = true; 1320 break; 1321 1322 /* always show sign */ 1323 case FLAG_PLUS: 1324 info->fShowSign = true; 1325 break; 1326 1327 /* use space if no sign present */ 1328 case FLAG_SPACE: 1329 info->fShowSign = true; 1330 info->fSpace = true; 1331 break; 1332 1333 /* use alternate form */ 1334 case FLAG_POUND: 1335 info->fAlt = true; 1336 break; 1337 1338 /* pad with leading zeroes */ 1339 case FLAG_ZERO: 1340 info->fZero = true; 1341 info->fPadChar = 0x0030; 1342 break; 1343 1344 /* pad character specified */ 1345 case FLAG_PAREN: 1346 1347 /* TODO test that all four are numbers */ 1348 /* first four characters are hex values for pad char */ 1349 info->fPadChar = (char16_t)ufmt_digitvalue(*alias++); 1350 info->fPadChar = (char16_t)((info->fPadChar * 16) + ufmt_digitvalue(*alias++)); 1351 info->fPadChar = (char16_t)((info->fPadChar * 16) + ufmt_digitvalue(*alias++)); 1352 info->fPadChar = (char16_t)((info->fPadChar * 16) + ufmt_digitvalue(*alias++)); 1353 1354 /* final character is ignored */ 1355 alias++; 1356 1357 break; 1358 } 1359 } 1360 1361 /* Get the width */ 1362 1363 /* width is specified out of line */ 1364 if(*alias == SPEC_ASTERISK) { 1365 1366 info->fWidth = -2; 1367 1368 /* Skip the '*' */ 1369 alias++; 1370 1371 /* Save the current position */ 1372 backup = alias; 1373 1374 /* handle positional parameters */ 1375 if(ISDIGIT(*alias)) { 1376 spec.fWidthPos = *alias++ - DIGIT_ZERO; 1377 1378 while(ISDIGIT(*alias)) { 1379 spec.fWidthPos *= 10; 1380 spec.fWidthPos += *alias++ - DIGIT_ZERO; 1381 } 1382 } 1383 1384 /* if there is no '$', don't read anything */ 1385 if(*alias != SPEC_DOLLARSIGN) { 1386 spec.fWidthPos = -1; 1387 alias = backup; 1388 } 1389 /* munge the '$' */ 1390 else 1391 alias++; 1392 } 1393 /* read the width, if present */ 1394 else if(ISDIGIT(*alias)){ 1395 info->fWidth = *alias++ - DIGIT_ZERO; 1396 1397 while(ISDIGIT(*alias)) { 1398 info->fWidth *= 10; 1399 info->fWidth += *alias++ - DIGIT_ZERO; 1400 } 1401 } 1402 1403 /* Get the precision */ 1404 1405 if(*alias == SPEC_PERIOD) { 1406 1407 /* eat up the '.' */ 1408 alias++; 1409 1410 /* precision is specified out of line */ 1411 if(*alias == SPEC_ASTERISK) { 1412 1413 info->fPrecision = -2; 1414 1415 /* Skip the '*' */ 1416 alias++; 1417 1418 /* save the current position */ 1419 backup = alias; 1420 1421 /* handle positional parameters */ 1422 if(ISDIGIT(*alias)) { 1423 spec.fPrecisionPos = *alias++ - DIGIT_ZERO; 1424 1425 while(ISDIGIT(*alias)) { 1426 spec.fPrecisionPos *= 10; 1427 spec.fPrecisionPos += *alias++ - DIGIT_ZERO; 1428 } 1429 1430 /* if there is no '$', don't read anything */ 1431 if(*alias != SPEC_DOLLARSIGN) { 1432 spec.fPrecisionPos = -1; 1433 alias = backup; 1434 } 1435 else { 1436 /* munge the '$' */ 1437 alias++; 1438 } 1439 } 1440 } 1441 /* read the precision */ 1442 else if(ISDIGIT(*alias)){ 1443 info->fPrecision = *alias++ - DIGIT_ZERO; 1444 1445 while(ISDIGIT(*alias)) { 1446 info->fPrecision *= 10; 1447 info->fPrecision += *alias++ - DIGIT_ZERO; 1448 } 1449 } 1450 } 1451 1452 /* Get any modifiers */ 1453 if(ISMOD(*alias)) { 1454 switch(*alias++) { 1455 1456 /* short */ 1457 case MOD_H: 1458 info->fIsShort = true; 1459 break; 1460 1461 /* long or long long */ 1462 case MOD_LOWERL: 1463 if(*alias == MOD_LOWERL) { 1464 info->fIsLongLong = true; 1465 /* skip over the next 'l' */ 1466 alias++; 1467 } 1468 else 1469 info->fIsLong = true; 1470 break; 1471 1472 /* long double */ 1473 case MOD_L: 1474 info->fIsLongDouble = true; 1475 break; 1476 } 1477 } 1478 1479 /* finally, get the specifier letter */ 1480 info->fSpec = *alias++; 1481 info->fOrigSpec = info->fSpec; 1482 1483 /* fill in the precision and width, if specified out of line */ 1484 1485 /* width specified out of line */ 1486 if(spec.fInfo.fWidth == -2) { 1487 if(spec.fWidthPos == -1) { 1488 /* read the width from the argument list */ 1489 info->fWidth = va_arg(ap, int32_t); 1490 } 1491 /* else handle positional parameter */ 1492 1493 /* if it's negative, take the absolute value and set left alignment */ 1494 if(info->fWidth < 0) { 1495 info->fWidth *= -1; /* Make positive */ 1496 info->fLeft = true; 1497 } 1498 } 1499 1500 /* precision specified out of line */ 1501 if(info->fPrecision == -2) { 1502 if(spec.fPrecisionPos == -1) { 1503 /* read the precision from the argument list */ 1504 info->fPrecision = va_arg(ap, int32_t); 1505 } 1506 /* else handle positional parameter */ 1507 1508 /* if it's negative, set it to zero */ 1509 if(info->fPrecision < 0) 1510 info->fPrecision = 0; 1511 } 1512 1513 handlerNum = (uint16_t)(info->fSpec - UPRINTF_BASE_FMT_HANDLERS); 1514 if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) { 1515 /* query the info function for argument information */ 1516 argType = g_u_printf_infos[ handlerNum ].info; 1517 1518 /* goto the correct argument on arg_list if position is specified */ 1519 if (spec.fArgPos > 0) { 1520 /* offset position by 1 */ 1521 spec.fArgPos--; 1522 switch(argType) { 1523 case ufmt_count: 1524 /* set the spec's width to the # of chars written */ 1525 info->fWidth = *written; 1526 /* fall through to set the pointer */ 1527 U_FALLTHROUGH; 1528 case ufmt_string: 1529 case ufmt_ustring: 1530 case ufmt_pointer: 1531 args.ptrValue = arglist[spec.fArgPos].ptrValue; 1532 break; 1533 case ufmt_char: 1534 case ufmt_uchar: 1535 case ufmt_int: 1536 args.int64Value = arglist[spec.fArgPos].int64Value; 1537 break; 1538 case ufmt_float: 1539 args.floatValue = arglist[spec.fArgPos].floatValue; 1540 break; 1541 case ufmt_double: 1542 args.doubleValue = arglist[spec.fArgPos].doubleValue; 1543 break; 1544 default: 1545 /* else args is ignored */ 1546 args.ptrValue = nullptr; 1547 break; 1548 } 1549 } else { /* no positional argument specified */ 1550 switch(argType) { 1551 case ufmt_count: 1552 /* set the spec's width to the # of chars written */ 1553 info->fWidth = *written; 1554 /* fall through to set the pointer */ 1555 U_FALLTHROUGH; 1556 case ufmt_string: 1557 case ufmt_ustring: 1558 case ufmt_pointer: 1559 args.ptrValue = va_arg(ap, void*); 1560 break; 1561 case ufmt_char: 1562 case ufmt_uchar: 1563 case ufmt_int: 1564 if (info->fIsLongLong) { 1565 args.int64Value = va_arg(ap, int64_t); 1566 } 1567 else { 1568 args.int64Value = va_arg(ap, int32_t); 1569 } 1570 break; 1571 case ufmt_float: 1572 args.floatValue = (float) va_arg(ap, double); 1573 break; 1574 case ufmt_double: 1575 args.doubleValue = va_arg(ap, double); 1576 break; 1577 default: 1578 /* else args is ignored */ 1579 args.ptrValue = nullptr; 1580 break; 1581 } 1582 } 1583 1584 /* call the handler function */ 1585 handler = g_u_printf_infos[ handlerNum ].handler; 1586 if (handler != nullptr) { 1587 *written += (*handler)(streamHandler, context, formatBundle, info, &args); 1588 } 1589 else { 1590 /* just echo unknown tags */ 1591 *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias)); 1592 } 1593 } 1594 else { 1595 /* just echo unknown tags */ 1596 *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias)); 1597 } 1598 } 1599 /* delete parsed argument list */ 1600 if (arglist != nullptr) { 1601 uprv_free(arglist); 1602 } 1603 /* return # of characters in this format that have been parsed. */ 1604 return (int32_t)(alias - fmt); 1605 } 1606 1607 #endif /* #if !UCONFIG_NO_FORMATTING */