-
- // Fraction digits.
- result.decimalDigits = result.decimalDigitsWithoutTrailingZeros = result.visibleDecimalDigitCount = 0;
- for (di = number.getDecimalAt(); di < number.getCount(); di++) {
- result.visibleDecimalDigitCount++;
- if (result.decimalDigits < 100000000000000000LL) {
- // 9223372036854775807 Largest 64 bit signed integer
- int32_t digitVal = number.getDigit(di) & 0x0f; // getDigit() returns a char, '0'-'9'.
- result.decimalDigits = result.decimalDigits * 10 + digitVal;
- if (digitVal > 0) {
- result.decimalDigitsWithoutTrailingZeros = result.decimalDigits;
- }
- }
- }
-
- result.hasIntegerValue = (result.decimalDigits == 0);
-
- // Trailing fraction zeros. The format specification may require more trailing
- // zeros than the numeric value. Add any such on now.
-
- int32_t minFractionDigits;
- if (areSignificantDigitsUsed()) {
- minFractionDigits = getMinimumSignificantDigits() - number.getDecimalAt();
- if (minFractionDigits < 0) {
- minFractionDigits = 0;
- }
- } else {
- minFractionDigits = getMinimumFractionDigits();
- }
- result.adjustForMinFractionDigits(minFractionDigits);
-
- return result;
-}
-
-
-//------------------------------------------------------------------------------
-
-UnicodeString&
-DecimalFormat::format(int32_t number,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition) const
-{
- return format((int64_t)number, appendTo, fieldPosition);
-}
-
-UnicodeString&
-DecimalFormat::format(int32_t number,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition,
- UErrorCode& status) const
-{
- return format((int64_t)number, appendTo, fieldPosition, status);
-}
-
-UnicodeString&
-DecimalFormat::format(int32_t number,
- UnicodeString& appendTo,
- FieldPositionIterator* posIter,
- UErrorCode& status) const
-{
- return format((int64_t)number, appendTo, posIter, status);
-}
-
-
-#if UCONFIG_FORMAT_FASTPATHS_49
-void DecimalFormat::handleChanged() {
- DecimalFormatInternal &data = internalData(fReserved);
-
- if(data.fFastFormatStatus == kFastpathUNKNOWN || data.fFastParseStatus == kFastpathUNKNOWN) {
- return; // still constructing. Wait.
- }
-
- data.fFastParseStatus = data.fFastFormatStatus = kFastpathNO;
-
-#if UCONFIG_HAVE_PARSEALLINPUT
- if(fParseAllInput == UNUM_NO) {
- debug("No Parse fastpath: fParseAllInput==UNUM_NO");
- } else
-#endif
- if (fFormatWidth!=0) {
- debug("No Parse fastpath: fFormatWidth");
- } else if(fPositivePrefix.length()>0) {
- debug("No Parse fastpath: positive prefix");
- } else if(fPositiveSuffix.length()>0) {
- debug("No Parse fastpath: positive suffix");
- } else if(fNegativePrefix.length()>1
- || ((fNegativePrefix.length()==1) && (fNegativePrefix.charAt(0)!=0x002D))) {
- debug("No Parse fastpath: negative prefix that isn't '-'");
- } else if(fNegativeSuffix.length()>0) {
- debug("No Parse fastpath: negative suffix");
- } else {
- data.fFastParseStatus = kFastpathYES;
- debug("parse fastpath: YES");
- }
-
- if (fGroupingSize!=0 && isGroupingUsed()) {
- debug("No format fastpath: fGroupingSize!=0 and grouping is used");
-#ifdef FMT_DEBUG
- printf("groupingsize=%d\n", fGroupingSize);
-#endif
- } else if(fGroupingSize2!=0 && isGroupingUsed()) {
- debug("No format fastpath: fGroupingSize2!=0");
- } else if(fUseExponentialNotation) {
- debug("No format fastpath: fUseExponentialNotation");
- } else if(fFormatWidth!=0) {
- debug("No format fastpath: fFormatWidth!=0");
- } else if(fMinSignificantDigits!=1) {
- debug("No format fastpath: fMinSignificantDigits!=1");
- } else if(fMultiplier!=NULL) {
- debug("No format fastpath: fMultiplier!=NULL");
- } else if(fScale!=0) {
- debug("No format fastpath: fScale!=0");
- } else if(0x0030 != getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0)) {
- debug("No format fastpath: 0x0030 != getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0)");
- } else if(fDecimalSeparatorAlwaysShown) {
- debug("No format fastpath: fDecimalSeparatorAlwaysShown");
- } else if(getMinimumFractionDigits()>0) {
- debug("No format fastpath: fMinFractionDigits>0");
- } else if(fCurrencySignCount != fgCurrencySignCountZero) {
- debug("No format fastpath: fCurrencySignCount != fgCurrencySignCountZero");
- } else if(fRoundingIncrement!=0) {
- debug("No format fastpath: fRoundingIncrement!=0");
- } else {
- data.fFastFormatStatus = kFastpathYES;
- debug("format:kFastpathYES!");
- }
-
-
-}
-#endif
-//------------------------------------------------------------------------------
-
-UnicodeString&
-DecimalFormat::format(int64_t number,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition) const
-{
- UErrorCode status = U_ZERO_ERROR; /* ignored */
- FieldPositionOnlyHandler handler(fieldPosition);
- return _format(number, appendTo, handler, status);
-}
-
-UnicodeString&
-DecimalFormat::format(int64_t number,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition,
- UErrorCode& status) const
-{
- FieldPositionOnlyHandler handler(fieldPosition);
- return _format(number, appendTo, handler, status);
-}
-
-UnicodeString&
-DecimalFormat::format(int64_t number,
- UnicodeString& appendTo,
- FieldPositionIterator* posIter,
- UErrorCode& status) const
-{
- FieldPositionIteratorHandler handler(posIter, status);
- return _format(number, appendTo, handler, status);
-}
-
-UnicodeString&
-DecimalFormat::_format(int64_t number,
- UnicodeString& appendTo,
- FieldPositionHandler& handler,
- UErrorCode &status) const
-{
- // Bottleneck function for formatting int64_t
- if (U_FAILURE(status)) {
- return appendTo;
- }
-
-#if UCONFIG_FORMAT_FASTPATHS_49
- // const UnicodeString *posPrefix = fPosPrefixPattern;
- // const UnicodeString *posSuffix = fPosSuffixPattern;
- // const UnicodeString *negSuffix = fNegSuffixPattern;
-
- const DecimalFormatInternal &data = internalData(fReserved);
-
-#ifdef FMT_DEBUG
- data.dump();
- printf("fastpath? [%d]\n", number);
-#endif
-
- if( data.fFastFormatStatus==kFastpathYES) {
-
-#define kZero 0x0030
- const int32_t MAX_IDX = MAX_DIGITS+2;
- UChar outputStr[MAX_IDX];
- int32_t destIdx = MAX_IDX;
- outputStr[--destIdx] = 0; // term
-
- int64_t n = number;
- if (number < 1) {
- // Negative numbers are slightly larger than positive
- // output the first digit (or the leading zero)
- outputStr[--destIdx] = (-(n % 10) + kZero);
- n /= -10;
- }
- // get any remaining digits
- while (n > 0) {
- outputStr[--destIdx] = (n % 10) + kZero;
- n /= 10;
- }
-
-
- // Slide the number to the start of the output str
- U_ASSERT(destIdx >= 0);
- int32_t length = MAX_IDX - destIdx -1;
- /*int32_t prefixLen = */ appendAffix(appendTo, number, handler, number<0, TRUE);
- int32_t maxIntDig = getMaximumIntegerDigits();
- int32_t destlength = length<=maxIntDig?length:maxIntDig; // dest length pinned to max int digits
-
- if(length>maxIntDig && fBoolFlags.contains(UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- }
-
- int32_t prependZero = getMinimumIntegerDigits() - destlength;
-
-#ifdef FMT_DEBUG
- printf("prependZero=%d, length=%d, minintdig=%d maxintdig=%d destlength=%d skip=%d\n", prependZero, length, getMinimumIntegerDigits(), maxIntDig, destlength, length-destlength);
-#endif
- int32_t intBegin = appendTo.length();
-
- while((prependZero--)>0) {
- appendTo.append((UChar)0x0030); // '0'
- }
-
- appendTo.append(outputStr+destIdx+
- (length-destlength), // skip any leading digits
- destlength);
- handler.addAttribute(kIntegerField, intBegin, appendTo.length());
-
- /*int32_t suffixLen =*/ appendAffix(appendTo, number, handler, number<0, FALSE);
-
- //outputStr[length]=0;
-
-#ifdef FMT_DEBUG
- printf("Writing [%s] length [%d] max %d for [%d]\n", outputStr+destIdx, length, MAX_IDX, number);
-#endif
-
-#undef kZero
-
- return appendTo;
- } // end fastpath
-#endif
-
- // Else the slow way - via DigitList
- DigitList digits;
- digits.set(number);
- return _format(digits, appendTo, handler, status);
-}
-
-//------------------------------------------------------------------------------
-
-UnicodeString&
-DecimalFormat::format( double number,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition) const
-{
- UErrorCode status = U_ZERO_ERROR; /* ignored */
- FieldPositionOnlyHandler handler(fieldPosition);
- return _format(number, appendTo, handler, status);
-}
-
-UnicodeString&
-DecimalFormat::format( double number,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition,
- UErrorCode& status) const
-{
- FieldPositionOnlyHandler handler(fieldPosition);
- return _format(number, appendTo, handler, status);
-}
-
-UnicodeString&
-DecimalFormat::format( double number,
- UnicodeString& appendTo,
- FieldPositionIterator* posIter,
- UErrorCode& status) const
-{
- FieldPositionIteratorHandler handler(posIter, status);
- return _format(number, appendTo, handler, status);
-}
-
-UnicodeString&
-DecimalFormat::_format( double number,
- UnicodeString& appendTo,
- FieldPositionHandler& handler,
- UErrorCode &status) const
-{
- if (U_FAILURE(status)) {
- return appendTo;
- }
- // Special case for NaN, sets the begin and end index to be the
- // the string length of localized name of NaN.
- // TODO: let NaNs go through DigitList.
- if (uprv_isNaN(number))
- {
- int begin = appendTo.length();
- appendTo += getConstSymbol(DecimalFormatSymbols::kNaNSymbol);
-
- handler.addAttribute(kIntegerField, begin, appendTo.length());
-
- addPadding(appendTo, handler, 0, 0);
- return appendTo;
- }
-
- DigitList digits;
- digits.set(number);
- _format(digits, appendTo, handler, status);
- // No way to return status from here.
- return appendTo;
-}
-
-//------------------------------------------------------------------------------
-
-
-UnicodeString&
-DecimalFormat::format(const StringPiece &number,
- UnicodeString &toAppendTo,
- FieldPositionIterator *posIter,
- UErrorCode &status) const
-{
-#if UCONFIG_FORMAT_FASTPATHS_49
- // don't bother if the int64 path is not optimized
- int32_t len = number.length();
-
- if(len>0&&len<10) { /* 10 or more digits may not be an int64 */
- const char *data = number.data();
- int64_t num = 0;
- UBool neg = FALSE;
- UBool ok = TRUE;
-
- int32_t start = 0;
-
- if(data[start]=='+') {
- start++;
- } else if(data[start]=='-') {
- neg=TRUE;
- start++;
- }
-
- int32_t place = 1; /* 1, 10, ... */
- for(int32_t i=len-1;i>=start;i--) {
- if(data[i]>='0'&&data[i]<='9') {
- num+=place*(int64_t)(data[i]-'0');
- } else {
- ok=FALSE;
- break;
- }
- place *= 10;
- }
-
- if(ok) {
- if(neg) {
- num = -num;// add minus bit
- }
- // format as int64_t
- return format(num, toAppendTo, posIter, status);
- }
- // else fall through
- }
-#endif
-
- DigitList dnum;
- dnum.set(number, status);
- if (U_FAILURE(status)) {
- return toAppendTo;
- }
- FieldPositionIteratorHandler handler(posIter, status);
- _format(dnum, toAppendTo, handler, status);
- return toAppendTo;
-}
-
-
-UnicodeString&
-DecimalFormat::format(const DigitList &number,
- UnicodeString &appendTo,
- FieldPositionIterator *posIter,
- UErrorCode &status) const {
- FieldPositionIteratorHandler handler(posIter, status);
- _format(number, appendTo, handler, status);
- return appendTo;
-}
-
-
-
-UnicodeString&
-DecimalFormat::format(const DigitList &number,
- UnicodeString& appendTo,
- FieldPosition& pos,
- UErrorCode &status) const {
- FieldPositionOnlyHandler handler(pos);
- _format(number, appendTo, handler, status);
- return appendTo;
-}
-
-DigitList&
-DecimalFormat::_round(const DigitList &number, DigitList &adjustedNum, UBool& isNegative, UErrorCode &status) const {
- if (U_FAILURE(status)) {
- return adjustedNum;
- }
-
- // note: number and adjustedNum may refer to the same DigitList, in cases where a copy
- // is not needed by the caller.
-
- adjustedNum = number;
- isNegative = false;
- if (number.isNaN()) {
- return adjustedNum;
- }
-
- // Do this BEFORE checking to see if value is infinite or negative! Sets the
- // begin and end index to be length of the string composed of
- // localized name of Infinite and the positive/negative localized
- // signs.
-
- adjustedNum.setRoundingMode(fRoundingMode);
- if (fMultiplier != NULL) {
- adjustedNum.mult(*fMultiplier, status);
- if (U_FAILURE(status)) {
- return adjustedNum;
- }
- }
-
- if (fScale != 0) {
- DigitList ten;
- ten.set((int32_t)10);
- if (fScale > 0) {
- for (int32_t i = fScale ; i > 0 ; i--) {
- adjustedNum.mult(ten, status);
- if (U_FAILURE(status)) {
- return adjustedNum;
- }
- }
- } else {
- for (int32_t i = fScale ; i < 0 ; i++) {
- adjustedNum.div(ten, status);
- if (U_FAILURE(status)) {
- return adjustedNum;
- }
- }
- }
- }
-
- /*
- * Note: sign is important for zero as well as non-zero numbers.
- * Proper detection of -0.0 is needed to deal with the
- * issues raised by bugs 4106658, 4106667, and 4147706. Liu 7/6/98.
- */
- isNegative = !adjustedNum.isPositive();
-
- // Apply rounding after multiplier
-
- adjustedNum.fContext.status &= ~DEC_Inexact;
- if (fRoundingIncrement != NULL) {
- adjustedNum.div(*fRoundingIncrement, status);
- adjustedNum.toIntegralValue();
- adjustedNum.mult(*fRoundingIncrement, status);
- adjustedNum.trim();
- if (U_FAILURE(status)) {
- return adjustedNum;
- }
- }
- if (fRoundingMode == kRoundUnnecessary && (adjustedNum.fContext.status & DEC_Inexact)) {
- status = U_FORMAT_INEXACT_ERROR;
- return adjustedNum;
- }
-
- if (adjustedNum.isInfinite()) {
- return adjustedNum;
- }
-
- if (fUseExponentialNotation || areSignificantDigitsUsed()) {
- int32_t sigDigits = precision();
- if (sigDigits > 0) {
- adjustedNum.round(sigDigits);
- // Travis Keep (21/2/2014): Calling round on a digitList does not necessarily
- // preserve the sign of that digit list. Preserving the sign is especially
- // important when formatting -0.0 for instance. Not preserving the sign seems
- // like a bug because I cannot think of any case where the sign would actually
- // have to change when rounding. For now, we preserve the sign by setting the
- // positive attribute directly.
- adjustedNum.setPositive(!isNegative);
- }
- } else {
- // Fixed point format. Round to a set number of fraction digits.
- int32_t numFractionDigits = precision();
- adjustedNum.roundFixedPoint(numFractionDigits);
- }
- if (fRoundingMode == kRoundUnnecessary && (adjustedNum.fContext.status & DEC_Inexact)) {
- status = U_FORMAT_INEXACT_ERROR;
- return adjustedNum;
- }
- return adjustedNum;
-}
-
-UnicodeString&
-DecimalFormat::_format(const DigitList &number,
- UnicodeString& appendTo,
- FieldPositionHandler& handler,
- UErrorCode &status) const
-{
- if (U_FAILURE(status)) {
- return appendTo;
- }
-
- // Special case for NaN, sets the begin and end index to be the
- // the string length of localized name of NaN.
- if (number.isNaN())
- {
- int begin = appendTo.length();
- appendTo += getConstSymbol(DecimalFormatSymbols::kNaNSymbol);
-
- handler.addAttribute(kIntegerField, begin, appendTo.length());
-
- addPadding(appendTo, handler, 0, 0);
- return appendTo;
- }
-
- DigitList adjustedNum;
- UBool isNegative;
- _round(number, adjustedNum, isNegative, status);
- if (U_FAILURE(status)) {
- return appendTo;
- }
-
- // Special case for INFINITE,
- if (adjustedNum.isInfinite()) {
- int32_t prefixLen = appendAffix(appendTo, adjustedNum.getDouble(), handler, isNegative, TRUE);
-
- int begin = appendTo.length();
- appendTo += getConstSymbol(DecimalFormatSymbols::kInfinitySymbol);
-
- handler.addAttribute(kIntegerField, begin, appendTo.length());
-
- int32_t suffixLen = appendAffix(appendTo, adjustedNum.getDouble(), handler, isNegative, FALSE);
-
- addPadding(appendTo, handler, prefixLen, suffixLen);
- return appendTo;
- }
- return subformat(appendTo, handler, adjustedNum, FALSE, status);
-}
-
-/**
- * Return true if a grouping separator belongs at the given
- * position, based on whether grouping is in use and the values of
- * the primary and secondary grouping interval.
- * @param pos the number of integer digits to the right of
- * the current position. Zero indicates the position after the
- * rightmost integer digit.
- * @return true if a grouping character belongs at the current
- * position.
- */
-UBool DecimalFormat::isGroupingPosition(int32_t pos) const {
- UBool result = FALSE;
- if (isGroupingUsed() && (pos > 0) && (fGroupingSize > 0)) {
- if ((fGroupingSize2 > 0) && (pos > fGroupingSize)) {
- result = ((pos - fGroupingSize) % fGroupingSize2) == 0;
- } else {
- result = pos % fGroupingSize == 0;
- }
- }
- return result;
-}
-
-//------------------------------------------------------------------------------
-
-/**
- * Complete the formatting of a finite number. On entry, the DigitList must
- * be filled in with the correct digits.
- */
-UnicodeString&
-DecimalFormat::subformat(UnicodeString& appendTo,
- FieldPositionHandler& handler,
- DigitList& digits,
- UBool isInteger,
- UErrorCode& status) const
-{
- // char zero = '0';
- // DigitList returns digits as '0' thru '9', so we will need to
- // always need to subtract the character 0 to get the numeric value to use for indexing.
-
- UChar32 localizedDigits[10];
- localizedDigits[0] = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
- localizedDigits[1] = getConstSymbol(DecimalFormatSymbols::kOneDigitSymbol).char32At(0);
- localizedDigits[2] = getConstSymbol(DecimalFormatSymbols::kTwoDigitSymbol).char32At(0);
- localizedDigits[3] = getConstSymbol(DecimalFormatSymbols::kThreeDigitSymbol).char32At(0);
- localizedDigits[4] = getConstSymbol(DecimalFormatSymbols::kFourDigitSymbol).char32At(0);
- localizedDigits[5] = getConstSymbol(DecimalFormatSymbols::kFiveDigitSymbol).char32At(0);
- localizedDigits[6] = getConstSymbol(DecimalFormatSymbols::kSixDigitSymbol).char32At(0);
- localizedDigits[7] = getConstSymbol(DecimalFormatSymbols::kSevenDigitSymbol).char32At(0);
- localizedDigits[8] = getConstSymbol(DecimalFormatSymbols::kEightDigitSymbol).char32At(0);
- localizedDigits[9] = getConstSymbol(DecimalFormatSymbols::kNineDigitSymbol).char32At(0);
-
- const UnicodeString *grouping ;
- if(fCurrencySignCount == fgCurrencySignCountZero) {
- grouping = &getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
- }else{
- grouping = &getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol);
- }
- const UnicodeString *decimal;
- if(fCurrencySignCount == fgCurrencySignCountZero) {
- decimal = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
- } else {
- decimal = &getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
- }
- UBool useSigDig = areSignificantDigitsUsed();
- int32_t maxIntDig = getMaximumIntegerDigits();
- int32_t minIntDig = getMinimumIntegerDigits();
-
- // Appends the prefix.
- double doubleValue = digits.getDouble();
- int32_t prefixLen = appendAffix(appendTo, doubleValue, handler, !digits.isPositive(), TRUE);
-
- if (fUseExponentialNotation)
- {
- int currentLength = appendTo.length();
- int intBegin = currentLength;
- int intEnd = -1;
- int fracBegin = -1;
-
- int32_t minFracDig = 0;
- if (useSigDig) {
- maxIntDig = minIntDig = 1;
- minFracDig = getMinimumSignificantDigits() - 1;
- } else {
- minFracDig = getMinimumFractionDigits();
- if (maxIntDig > kMaxScientificIntegerDigits) {
- maxIntDig = 1;
- if (maxIntDig < minIntDig) {
- maxIntDig = minIntDig;
- }
- }
- if (maxIntDig > minIntDig) {
- minIntDig = 1;
- }
- }
-
- // Minimum integer digits are handled in exponential format by
- // adjusting the exponent. For example, 0.01234 with 3 minimum
- // integer digits is "123.4E-4".
-
- // Maximum integer digits are interpreted as indicating the
- // repeating range. This is useful for engineering notation, in
- // which the exponent is restricted to a multiple of 3. For
- // example, 0.01234 with 3 maximum integer digits is "12.34e-3".
- // If maximum integer digits are defined and are larger than
- // minimum integer digits, then minimum integer digits are
- // ignored.
- digits.reduce(); // Removes trailing zero digits.
- int32_t exponent = digits.getDecimalAt();
- if (maxIntDig > 1 && maxIntDig != minIntDig) {
- // A exponent increment is defined; adjust to it.
- exponent = (exponent > 0) ? (exponent - 1) / maxIntDig
- : (exponent / maxIntDig) - 1;
- exponent *= maxIntDig;
- } else {
- // No exponent increment is defined; use minimum integer digits.
- // If none is specified, as in "#E0", generate 1 integer digit.
- exponent -= (minIntDig > 0 || minFracDig > 0)
- ? minIntDig : 1;
- }
-
- // We now output a minimum number of digits, and more if there
- // are more digits, up to the maximum number of digits. We
- // place the decimal point after the "integer" digits, which
- // are the first (decimalAt - exponent) digits.
- int32_t minimumDigits = minIntDig + minFracDig;
- // The number of integer digits is handled specially if the number
- // is zero, since then there may be no digits.
- int32_t integerDigits = digits.isZero() ? minIntDig :
- digits.getDecimalAt() - exponent;
- int32_t totalDigits = digits.getCount();
- if (minimumDigits > totalDigits)
- totalDigits = minimumDigits;
- if (integerDigits > totalDigits)
- totalDigits = integerDigits;
-
- // totalDigits records total number of digits needs to be processed
- int32_t i;
- for (i=0; i<totalDigits; ++i)
- {
- if (i == integerDigits)
- {
- intEnd = appendTo.length();
- handler.addAttribute(kIntegerField, intBegin, intEnd);
-
- appendTo += *decimal;
-
- fracBegin = appendTo.length();
- handler.addAttribute(kDecimalSeparatorField, fracBegin - 1, fracBegin);
- }
- // Restores the digit character or pads the buffer with zeros.
- UChar32 c = (UChar32)((i < digits.getCount()) ?
- localizedDigits[digits.getDigitValue(i)] :
- localizedDigits[0]);
- appendTo += c;
- }
-
- currentLength = appendTo.length();
-
- if (intEnd < 0) {
- handler.addAttribute(kIntegerField, intBegin, currentLength);
- }
- if (fracBegin > 0) {
- handler.addAttribute(kFractionField, fracBegin, currentLength);
- }
-
- // The exponent is output using the pattern-specified minimum
- // exponent digits. There is no maximum limit to the exponent
- // digits, since truncating the exponent would appendTo in an
- // unacceptable inaccuracy.
- appendTo += getConstSymbol(DecimalFormatSymbols::kExponentialSymbol);
-
- handler.addAttribute(kExponentSymbolField, currentLength, appendTo.length());
- currentLength = appendTo.length();
-
- // For zero values, we force the exponent to zero. We
- // must do this here, and not earlier, because the value
- // is used to determine integer digit count above.
- if (digits.isZero())
- exponent = 0;
-
- if (exponent < 0) {
- appendTo += getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
- handler.addAttribute(kExponentSignField, currentLength, appendTo.length());
- } else if (fExponentSignAlwaysShown) {
- appendTo += getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
- handler.addAttribute(kExponentSignField, currentLength, appendTo.length());
- }
-
- currentLength = appendTo.length();
-
- DigitList expDigits;
- expDigits.set(exponent);
- {
- int expDig = fMinExponentDigits;
- if (fUseExponentialNotation && expDig < 1) {
- expDig = 1;
- }
- for (i=expDigits.getDecimalAt(); i<expDig; ++i)
- appendTo += (localizedDigits[0]);
- }
- for (i=0; i<expDigits.getDecimalAt(); ++i)
- {
- UChar32 c = (UChar32)((i < expDigits.getCount()) ?
- localizedDigits[expDigits.getDigitValue(i)] :
- localizedDigits[0]);
- appendTo += c;
- }
-
- handler.addAttribute(kExponentField, currentLength, appendTo.length());
- }
- else // Not using exponential notation
- {
- int currentLength = appendTo.length();
- int intBegin = currentLength;
-
- int32_t sigCount = 0;
- int32_t minSigDig = getMinimumSignificantDigits();
- int32_t maxSigDig = getMaximumSignificantDigits();
- if (!useSigDig) {
- minSigDig = 0;
- maxSigDig = INT32_MAX;
- }
-
- // Output the integer portion. Here 'count' is the total
- // number of integer digits we will display, including both
- // leading zeros required to satisfy getMinimumIntegerDigits,
- // and actual digits present in the number.
- int32_t count = useSigDig ?
- _max(1, digits.getDecimalAt()) : minIntDig;
- if (digits.getDecimalAt() > 0 && count < digits.getDecimalAt()) {
- count = digits.getDecimalAt();
- }
-
- // Handle the case where getMaximumIntegerDigits() is smaller
- // than the real number of integer digits. If this is so, we
- // output the least significant max integer digits. For example,
- // the value 1997 printed with 2 max integer digits is just "97".
-
- int32_t digitIndex = 0; // Index into digitList.fDigits[]
- if (count > maxIntDig && maxIntDig >= 0) {
- count = maxIntDig;
- digitIndex = digits.getDecimalAt() - count;
- if(fBoolFlags.contains(UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- }
- }
-
- int32_t sizeBeforeIntegerPart = appendTo.length();
-
- int32_t i;
- for (i=count-1; i>=0; --i)
- {
- if (i < digits.getDecimalAt() && digitIndex < digits.getCount() &&
- sigCount < maxSigDig) {
- // Output a real digit
- appendTo += (UChar32)localizedDigits[digits.getDigitValue(digitIndex++)];
- ++sigCount;
- }
- else
- {
- // Output a zero (leading or trailing)
- appendTo += localizedDigits[0];
- if (sigCount > 0) {
- ++sigCount;
- }
- }
-
- // Output grouping separator if necessary.
- if (isGroupingPosition(i)) {
- currentLength = appendTo.length();
- appendTo.append(*grouping);
- handler.addAttribute(kGroupingSeparatorField, currentLength, appendTo.length());
- }
- }
-
- // This handles the special case of formatting 0. For zero only, we count the
- // zero to the left of the decimal point as one signficant digit. Ordinarily we
- // do not count any leading 0's as significant. If the number we are formatting
- // is not zero, then either sigCount or digits.getCount() will be non-zero.
- if (sigCount == 0 && digits.getCount() == 0) {
- sigCount = 1;
- }
-
- // TODO(dlf): this looks like it was a bug, we marked the int field as ending
- // before the zero was generated.
- // Record field information for caller.
- // if (fieldPosition.getField() == NumberFormat::kIntegerField)
- // fieldPosition.setEndIndex(appendTo.length());
-
- // Determine whether or not there are any printable fractional
- // digits. If we've used up the digits we know there aren't.
- UBool fractionPresent = (!isInteger && digitIndex < digits.getCount()) ||
- (useSigDig ? (sigCount < minSigDig) : (getMinimumFractionDigits() > 0));
-
- // If there is no fraction present, and we haven't printed any
- // integer digits, then print a zero. Otherwise we won't print
- // _any_ digits, and we won't be able to parse this string.
- if (!fractionPresent && appendTo.length() == sizeBeforeIntegerPart)
- appendTo += localizedDigits[0];
-
- currentLength = appendTo.length();
- handler.addAttribute(kIntegerField, intBegin, currentLength);
-
- // Output the decimal separator if we always do so.
- if (fDecimalSeparatorAlwaysShown || fractionPresent) {
- appendTo += *decimal;
- handler.addAttribute(kDecimalSeparatorField, currentLength, appendTo.length());
- currentLength = appendTo.length();
- }
-
- int fracBegin = currentLength;
-
- count = useSigDig ? INT32_MAX : getMaximumFractionDigits();
- if (useSigDig && (sigCount == maxSigDig ||
- (sigCount >= minSigDig && digitIndex == digits.getCount()))) {
- count = 0;
- }
-
- for (i=0; i < count; ++i) {
- // Here is where we escape from the loop. We escape
- // if we've output the maximum fraction digits
- // (specified in the for expression above). We also
- // stop when we've output the minimum digits and
- // either: we have an integer, so there is no
- // fractional stuff to display, or we're out of
- // significant digits.
- if (!useSigDig && i >= getMinimumFractionDigits() &&
- (isInteger || digitIndex >= digits.getCount())) {
- break;
- }
-
- // Output leading fractional zeros. These are zeros
- // that come after the decimal but before any
- // significant digits. These are only output if
- // abs(number being formatted) < 1.0.
- if (-1-i > (digits.getDecimalAt()-1)) {
- appendTo += localizedDigits[0];
- continue;
- }
-
- // Output a digit, if we have any precision left, or a
- // zero if we don't. We don't want to output noise digits.
- if (!isInteger && digitIndex < digits.getCount()) {
- appendTo += (UChar32)localizedDigits[digits.getDigitValue(digitIndex++)];
- } else {
- appendTo += localizedDigits[0];
- }
-
- // If we reach the maximum number of significant
- // digits, or if we output all the real digits and
- // reach the minimum, then we are done.
- ++sigCount;
- if (useSigDig &&
- (sigCount == maxSigDig ||
- (digitIndex == digits.getCount() && sigCount >= minSigDig))) {
- break;
- }
- }
-
- handler.addAttribute(kFractionField, fracBegin, appendTo.length());
- }
-
- int32_t suffixLen = appendAffix(appendTo, doubleValue, handler, !digits.isPositive(), FALSE);
-
- addPadding(appendTo, handler, prefixLen, suffixLen);
- return appendTo;
-}
-
-/**
- * Inserts the character fPad as needed to expand result to fFormatWidth.
- * @param result the string to be padded
- */
-void DecimalFormat::addPadding(UnicodeString& appendTo,
- FieldPositionHandler& handler,
- int32_t prefixLen,
- int32_t suffixLen) const
-{
- if (fFormatWidth > 0) {
- int32_t len = fFormatWidth - appendTo.length();
- if (len > 0) {
- UnicodeString padding;
- for (int32_t i=0; i<len; ++i) {
- padding += fPad;
- }
- switch (fPadPosition) {
- case kPadAfterPrefix:
- appendTo.insert(prefixLen, padding);
- break;
- case kPadBeforePrefix:
- appendTo.insert(0, padding);
- break;
- case kPadBeforeSuffix:
- appendTo.insert(appendTo.length() - suffixLen, padding);
- break;
- case kPadAfterSuffix:
- appendTo += padding;
- break;
- }
- if (fPadPosition == kPadBeforePrefix || fPadPosition == kPadAfterPrefix) {
- handler.shiftLast(len);
- }
- }
- }
-}
-
-//------------------------------------------------------------------------------
-
-void
-DecimalFormat::parse(const UnicodeString& text,
- Formattable& result,
- ParsePosition& parsePosition) const {
- parse(text, result, parsePosition, NULL);
-}
-
-CurrencyAmount* DecimalFormat::parseCurrency(const UnicodeString& text,
- ParsePosition& pos) const {
- Formattable parseResult;
- int32_t start = pos.getIndex();
- UChar curbuf[4] = {};
- parse(text, parseResult, pos, curbuf);
- if (pos.getIndex() != start) {
- UErrorCode ec = U_ZERO_ERROR;
- LocalPointer<CurrencyAmount> currAmt(new CurrencyAmount(parseResult, curbuf, ec));
- if (U_FAILURE(ec)) {
- pos.setIndex(start); // indicate failure
- } else {
- return currAmt.orphan();
- }
- }
- return NULL;
-}
-
-/**
- * Parses the given text as a number, optionally providing a currency amount.
- * @param text the string to parse
- * @param result output parameter for the numeric result.
- * @param parsePosition input-output position; on input, the
- * position within text to match; must have 0 <= pos.getIndex() <
- * text.length(); on output, the position after the last matched
- * character. If the parse fails, the position in unchanged upon
- * output.
- * @param currency if non-NULL, it should point to a 4-UChar buffer.
- * In this case the text is parsed as a currency format, and the
- * ISO 4217 code for the parsed currency is put into the buffer.
- * Otherwise the text is parsed as a non-currency format.
- */
-void DecimalFormat::parse(const UnicodeString& text,
- Formattable& result,
- ParsePosition& parsePosition,
- UChar* currency) const {
- int32_t startIdx, backup;
- int32_t i = startIdx = backup = parsePosition.getIndex();
-
- // clear any old contents in the result. In particular, clears any DigitList
- // that it may be holding.
- result.setLong(0);
- if (currency != NULL) {
- for (int32_t ci=0; ci<4; ci++) {
- currency[ci] = 0;
- }
- }
-
- // Handle NaN as a special case:
-
- // Skip padding characters, if around prefix
- if (fFormatWidth > 0 && (fPadPosition == kPadBeforePrefix ||
- fPadPosition == kPadAfterPrefix)) {
- i = skipPadding(text, i);
- }
-
- if (isLenient()) {
- // skip any leading whitespace
- i = backup = skipUWhiteSpace(text, i);
- }
-
- // If the text is composed of the representation of NaN, returns NaN.length
- const UnicodeString *nan = &getConstSymbol(DecimalFormatSymbols::kNaNSymbol);
- int32_t nanLen = (text.compare(i, nan->length(), *nan)
- ? 0 : nan->length());
- if (nanLen) {
- i += nanLen;
- if (fFormatWidth > 0 && (fPadPosition == kPadBeforeSuffix ||
- fPadPosition == kPadAfterSuffix)) {
- i = skipPadding(text, i);
- }
- parsePosition.setIndex(i);
- result.setDouble(uprv_getNaN());
- return;
- }
-
- // NaN parse failed; start over
- i = backup;
- parsePosition.setIndex(i);
-
- // status is used to record whether a number is infinite.
- UBool status[fgStatusLength];
-
- DigitList *digits = result.getInternalDigitList(); // get one from the stack buffer
- if (digits == NULL) {
- return; // no way to report error from here.
- }
-
- if (fCurrencySignCount != fgCurrencySignCountZero) {
- if (!parseForCurrency(text, parsePosition, *digits,
- status, currency)) {
- return;
- }
- } else {
- if (!subparse(text,
- fNegPrefixPattern, fNegSuffixPattern,
- fPosPrefixPattern, fPosSuffixPattern,
- FALSE, UCURR_SYMBOL_NAME,
- parsePosition, *digits, status, currency)) {
- debug("!subparse(...) - rewind");
- parsePosition.setIndex(startIdx);
- return;
- }
- }
-
- // Handle infinity
- if (status[fgStatusInfinite]) {
- double inf = uprv_getInfinity();
- result.setDouble(digits->isPositive() ? inf : -inf);
- // TODO: set the dl to infinity, and let it fall into the code below.
- }
-
- else {
-
- if (fMultiplier != NULL) {
- UErrorCode ec = U_ZERO_ERROR;
- digits->div(*fMultiplier, ec);
- }
-
- if (fScale != 0) {
- DigitList ten;
- ten.set((int32_t)10);
- if (fScale > 0) {
- for (int32_t i = fScale; i > 0; i--) {
- UErrorCode ec = U_ZERO_ERROR;
- digits->div(ten,ec);
- }
- } else {
- for (int32_t i = fScale; i < 0; i++) {
- UErrorCode ec = U_ZERO_ERROR;
- digits->mult(ten,ec);
- }
- }
- }
-
- // Negative zero special case:
- // if parsing integerOnly, change to +0, which goes into an int32 in a Formattable.
- // if not parsing integerOnly, leave as -0, which a double can represent.
- if (digits->isZero() && !digits->isPositive() && isParseIntegerOnly()) {
- digits->setPositive(TRUE);
- }
- result.adoptDigitList(digits);
- }
-}
-
-
-
-UBool
-DecimalFormat::parseForCurrency(const UnicodeString& text,
- ParsePosition& parsePosition,
- DigitList& digits,
- UBool* status,
- UChar* currency) const {
- int origPos = parsePosition.getIndex();
- int maxPosIndex = origPos;
- int maxErrorPos = -1;
- // First, parse against current pattern.
- // Since current pattern could be set by applyPattern(),
- // it could be an arbitrary pattern, and it may not be the one
- // defined in current locale.
- UBool tmpStatus[fgStatusLength];
- ParsePosition tmpPos(origPos);
- DigitList tmpDigitList;
- UBool found;
- if (fStyle == UNUM_CURRENCY_PLURAL) {
- found = subparse(text,
- fNegPrefixPattern, fNegSuffixPattern,
- fPosPrefixPattern, fPosSuffixPattern,
- TRUE, UCURR_LONG_NAME,
- tmpPos, tmpDigitList, tmpStatus, currency);
- } else {
- found = subparse(text,
- fNegPrefixPattern, fNegSuffixPattern,
- fPosPrefixPattern, fPosSuffixPattern,
- TRUE, UCURR_SYMBOL_NAME,
- tmpPos, tmpDigitList, tmpStatus, currency);
- }
- if (found) {
- if (tmpPos.getIndex() > maxPosIndex) {
- maxPosIndex = tmpPos.getIndex();
- for (int32_t i = 0; i < fgStatusLength; ++i) {
- status[i] = tmpStatus[i];
- }
- digits = tmpDigitList;
- }
- } else {
- maxErrorPos = tmpPos.getErrorIndex();
- }
- // Then, parse against affix patterns.
- // Those are currency patterns and currency plural patterns.
- int32_t pos = -1;
- const UHashElement* element = NULL;
- while ( (element = fAffixPatternsForCurrency->nextElement(pos)) != NULL ) {
- const UHashTok valueTok = element->value;
- const AffixPatternsForCurrency* affixPtn = (AffixPatternsForCurrency*)valueTok.pointer;
- UBool tmpStatus[fgStatusLength];
- ParsePosition tmpPos(origPos);
- DigitList tmpDigitList;
-
-#ifdef FMT_DEBUG
- debug("trying affix for currency..");
- affixPtn->dump();
-#endif
-
- UBool result = subparse(text,
- &affixPtn->negPrefixPatternForCurrency,
- &affixPtn->negSuffixPatternForCurrency,
- &affixPtn->posPrefixPatternForCurrency,
- &affixPtn->posSuffixPatternForCurrency,
- TRUE, affixPtn->patternType,
- tmpPos, tmpDigitList, tmpStatus, currency);
- if (result) {
- found = true;
- if (tmpPos.getIndex() > maxPosIndex) {
- maxPosIndex = tmpPos.getIndex();
- for (int32_t i = 0; i < fgStatusLength; ++i) {
- status[i] = tmpStatus[i];
- }
- digits = tmpDigitList;
- }
- } else {
- maxErrorPos = (tmpPos.getErrorIndex() > maxErrorPos) ?
- tmpPos.getErrorIndex() : maxErrorPos;
- }
- }
- // Finally, parse against simple affix to find the match.
- // For example, in TestMonster suite,
- // if the to-be-parsed text is "-\u00A40,00".
- // complexAffixCompare will not find match,
- // since there is no ISO code matches "\u00A4",
- // and the parse stops at "\u00A4".
- // We will just use simple affix comparison (look for exact match)
- // to pass it.
- //
- // TODO: We should parse against simple affix first when
- // output currency is not requested. After the complex currency
- // parsing implementation was introduced, the default currency
- // instance parsing slowed down because of the new code flow.
- // I filed #10312 - Yoshito
- UBool tmpStatus_2[fgStatusLength];
- ParsePosition tmpPos_2(origPos);
- DigitList tmpDigitList_2;
-
- // Disable complex currency parsing and try it again.
- UBool result = subparse(text,
- &fNegativePrefix, &fNegativeSuffix,
- &fPositivePrefix, &fPositiveSuffix,
- FALSE /* disable complex currency parsing */, UCURR_SYMBOL_NAME,
- tmpPos_2, tmpDigitList_2, tmpStatus_2,
- currency);
- if (result) {
- if (tmpPos_2.getIndex() > maxPosIndex) {
- maxPosIndex = tmpPos_2.getIndex();
- for (int32_t i = 0; i < fgStatusLength; ++i) {
- status[i] = tmpStatus_2[i];
- }
- digits = tmpDigitList_2;
- }
- found = true;
- } else {
- maxErrorPos = (tmpPos_2.getErrorIndex() > maxErrorPos) ?
- tmpPos_2.getErrorIndex() : maxErrorPos;
- }
-
- if (!found) {
- //parsePosition.setIndex(origPos);
- parsePosition.setErrorIndex(maxErrorPos);
- } else {
- parsePosition.setIndex(maxPosIndex);
- parsePosition.setErrorIndex(-1);
- }
- return found;
-}
-
-
-/**
- * Parse the given text into a number. The text is parsed beginning at
- * parsePosition, until an unparseable character is seen.
- * @param text the string to parse.
- * @param negPrefix negative prefix.
- * @param negSuffix negative suffix.
- * @param posPrefix positive prefix.
- * @param posSuffix positive suffix.
- * @param complexCurrencyParsing whether it is complex currency parsing or not.
- * @param type the currency type to parse against, LONG_NAME only or not.
- * @param parsePosition The position at which to being parsing. Upon
- * return, the first unparsed character.
- * @param digits the DigitList to set to the parsed value.
- * @param status output param containing boolean status flags indicating
- * whether the value was infinite and whether it was positive.
- * @param currency return value for parsed currency, for generic
- * currency parsing mode, or NULL for normal parsing. In generic
- * currency parsing mode, any currency is parsed, not just the
- * currency that this formatter is set to.
- */
-UBool DecimalFormat::subparse(const UnicodeString& text,
- const UnicodeString* negPrefix,
- const UnicodeString* negSuffix,
- const UnicodeString* posPrefix,
- const UnicodeString* posSuffix,
- UBool complexCurrencyParsing,
- int8_t type,
- ParsePosition& parsePosition,
- DigitList& digits, UBool* status,
- UChar* currency) const
-{
- // The parsing process builds up the number as char string, in the neutral format that
- // will be acceptable to the decNumber library, then at the end passes that string
- // off for conversion to a decNumber.
- UErrorCode err = U_ZERO_ERROR;
- CharString parsedNum;
- digits.setToZero();
-
- int32_t position = parsePosition.getIndex();
- int32_t oldStart = position;
- int32_t textLength = text.length(); // One less pointer to follow
- UBool strictParse = !isLenient();
- UChar32 zero = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
- const UnicodeString *groupingString = &getConstSymbol(fCurrencySignCount == fgCurrencySignCountZero ?
- DecimalFormatSymbols::kGroupingSeparatorSymbol : DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol);
- UChar32 groupingChar = groupingString->char32At(0);
- int32_t groupingStringLength = groupingString->length();
- int32_t groupingCharLength = U16_LENGTH(groupingChar);
- UBool groupingUsed = isGroupingUsed();
-#ifdef FMT_DEBUG
- UChar dbgbuf[300];
- UnicodeString s(dbgbuf,0,300);;
- s.append((UnicodeString)"PARSE \"").append(text.tempSubString(position)).append((UnicodeString)"\" " );
-#define DBGAPPD(x) if(x) { s.append(UnicodeString(#x "=")); if(x->isEmpty()) { s.append(UnicodeString("<empty>")); } else { s.append(*x); } s.append(UnicodeString(" ")); } else { s.append(UnicodeString(#x "=NULL ")); }
- DBGAPPD(negPrefix);
- DBGAPPD(negSuffix);
- DBGAPPD(posPrefix);
- DBGAPPD(posSuffix);
- debugout(s);
- printf("currencyParsing=%d, fFormatWidth=%d, isParseIntegerOnly=%c text.length=%d negPrefLen=%d\n", currencyParsing, fFormatWidth, (isParseIntegerOnly())?'Y':'N', text.length(), negPrefix!=NULL?negPrefix->length():-1);
-#endif
-
- UBool fastParseOk = false; /* TRUE iff fast parse is OK */
- // UBool fastParseHadDecimal = FALSE; /* true if fast parse saw a decimal point. */
- const DecimalFormatInternal &data = internalData(fReserved);
- if((data.fFastParseStatus==kFastpathYES) &&
- fCurrencySignCount == fgCurrencySignCountZero &&
- // (negPrefix!=NULL&&negPrefix->isEmpty()) ||
- text.length()>0 &&
- text.length()<32 &&
- (posPrefix==NULL||posPrefix->isEmpty()) &&
- (posSuffix==NULL||posSuffix->isEmpty()) &&
- // (negPrefix==NULL||negPrefix->isEmpty()) &&
- // (negSuffix==NULL||(negSuffix->isEmpty()) ) &&
- TRUE) { // optimized path
- int j=position;
- int l=text.length();
- int digitCount=0;
- UChar32 ch = text.char32At(j);
- const UnicodeString *decimalString = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
- UChar32 decimalChar = 0;
- UBool intOnly = FALSE;
- UChar32 lookForGroup = (groupingUsed&&intOnly&&strictParse)?groupingChar:0;
-
- int32_t decimalCount = decimalString->countChar32(0,3);
- if(isParseIntegerOnly()) {
- decimalChar = 0; // not allowed
- intOnly = TRUE; // Don't look for decimals.
- } else if(decimalCount==1) {
- decimalChar = decimalString->char32At(0); // Look for this decimal
- } else if(decimalCount==0) {
- decimalChar=0; // NO decimal set
- } else {
- j=l+1;//Set counter to end of line, so that we break. Unknown decimal situation.
- }
-
-#ifdef FMT_DEBUG
- printf("Preparing to do fastpath parse: decimalChar=U+%04X, groupingChar=U+%04X, first ch=U+%04X intOnly=%c strictParse=%c\n",
- decimalChar, groupingChar, ch,
- (intOnly)?'y':'n',
- (strictParse)?'y':'n');
-#endif
- if(ch==0x002D) { // '-'
- j=l+1;//=break - negative number.
-
- /*
- parsedNum.append('-',err);
- j+=U16_LENGTH(ch);
- if(j<l) ch = text.char32At(j);
- */
- } else {
- parsedNum.append('+',err);
- }
- while(j<l) {
- int32_t digit = ch - zero;
- if(digit >=0 && digit <= 9) {
- parsedNum.append((char)(digit + '0'), err);
- if((digitCount>0) || digit!=0 || j==(l-1)) {
- digitCount++;
- }
- } else if(ch == 0) { // break out
- digitCount=-1;
- break;
- } else if(ch == decimalChar) {
- parsedNum.append((char)('.'), err);
- decimalChar=0; // no more decimals.
- // fastParseHadDecimal=TRUE;
- } else if(ch == lookForGroup) {
- // ignore grouping char. No decimals, so it has to be an ignorable grouping sep
- } else if(intOnly && (lookForGroup!=0) && !u_isdigit(ch)) {
- // parsing integer only and can fall through
- } else {
- digitCount=-1; // fail - fall through to slow parse
- break;
- }
- j+=U16_LENGTH(ch);
- ch = text.char32At(j); // for next
- }
- if(
- ((j==l)||intOnly) // end OR only parsing integer
- && (digitCount>0)) { // and have at least one digit
-#ifdef FMT_DEBUG
- printf("PP -> %d, good = [%s] digitcount=%d, fGroupingSize=%d fGroupingSize2=%d!\n", j, parsedNum.data(), digitCount, fGroupingSize, fGroupingSize2);
-#endif
- fastParseOk=true; // Fast parse OK!
-
-#ifdef SKIP_OPT
- debug("SKIP_OPT");
- /* for testing, try it the slow way. also */
- fastParseOk=false;
- parsedNum.clear();
-#else
- parsePosition.setIndex(position=j);
- status[fgStatusInfinite]=false;
-#endif
- } else {
- // was not OK. reset, retry
-#ifdef FMT_DEBUG
- printf("Fall through: j=%d, l=%d, digitCount=%d\n", j, l, digitCount);
-#endif
- parsedNum.clear();
- }
- } else {
-#ifdef FMT_DEBUG
- printf("Could not fastpath parse. ");
- printf("fFormatWidth=%d ", fFormatWidth);
- printf("text.length()=%d ", text.length());
- printf("posPrefix=%p posSuffix=%p ", posPrefix, posSuffix);
-
- printf("\n");
-#endif
- }
-
- if(!fastParseOk
-#if UCONFIG_HAVE_PARSEALLINPUT
- && fParseAllInput!=UNUM_YES
-#endif
- )
- {
- // Match padding before prefix
- if (fFormatWidth > 0 && fPadPosition == kPadBeforePrefix) {
- position = skipPadding(text, position);
- }
-
- // Match positive and negative prefixes; prefer longest match.
- int32_t posMatch = compareAffix(text, position, FALSE, TRUE, posPrefix, complexCurrencyParsing, type, currency);
- int32_t negMatch = compareAffix(text, position, TRUE, TRUE, negPrefix, complexCurrencyParsing, type, currency);
- if (posMatch >= 0 && negMatch >= 0) {
- if (posMatch > negMatch) {
- negMatch = -1;
- } else if (negMatch > posMatch) {
- posMatch = -1;
- }
- }
- if (posMatch >= 0) {
- position += posMatch;
- parsedNum.append('+', err);
- } else if (negMatch >= 0) {
- position += negMatch;
- parsedNum.append('-', err);
- } else if (strictParse){
- parsePosition.setErrorIndex(position);
- return FALSE;
- } else {
- // Temporary set positive. This might be changed after checking suffix
- parsedNum.append('+', err);
- }
-
- // Match padding before prefix
- if (fFormatWidth > 0 && fPadPosition == kPadAfterPrefix) {
- position = skipPadding(text, position);
- }
-
- if (! strictParse) {
- position = skipUWhiteSpace(text, position);
- }
-
- // process digits or Inf, find decimal position
- const UnicodeString *inf = &getConstSymbol(DecimalFormatSymbols::kInfinitySymbol);
- int32_t infLen = (text.compare(position, inf->length(), *inf)
- ? 0 : inf->length());
- position += infLen; // infLen is non-zero when it does equal to infinity
- status[fgStatusInfinite] = infLen != 0;
-
- if (infLen != 0) {
- parsedNum.append("Infinity", err);
- } else {
- // We now have a string of digits, possibly with grouping symbols,
- // and decimal points. We want to process these into a DigitList.
- // We don't want to put a bunch of leading zeros into the DigitList
- // though, so we keep track of the location of the decimal point,
- // put only significant digits into the DigitList, and adjust the
- // exponent as needed.
-
-
- UBool strictFail = FALSE; // did we exit with a strict parse failure?
- int32_t lastGroup = -1; // where did we last see a grouping separator?
- int32_t digitStart = position;
- int32_t gs2 = fGroupingSize2 == 0 ? fGroupingSize : fGroupingSize2;
-
- const UnicodeString *decimalString;
- if (fCurrencySignCount != fgCurrencySignCountZero) {
- decimalString = &getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
- } else {
- decimalString = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
- }
- UChar32 decimalChar = decimalString->char32At(0);
- int32_t decimalStringLength = decimalString->length();
- int32_t decimalCharLength = U16_LENGTH(decimalChar);
-
- UBool sawDecimal = FALSE;
- UChar32 sawDecimalChar = 0xFFFF;
- UBool sawGrouping = FALSE;
- UChar32 sawGroupingChar = 0xFFFF;
- UBool sawDigit = FALSE;
- int32_t backup = -1;
- int32_t digit;
-
- // equivalent grouping and decimal support
- const UnicodeSet *decimalSet = NULL;
- const UnicodeSet *groupingSet = NULL;
-
- if (decimalCharLength == decimalStringLength) {
- decimalSet = DecimalFormatStaticSets::getSimilarDecimals(decimalChar, strictParse);
- }
-
- if (groupingCharLength == groupingStringLength) {
- if (strictParse) {
- groupingSet = fStaticSets->fStrictDefaultGroupingSeparators;
- } else {
- groupingSet = fStaticSets->fDefaultGroupingSeparators;
- }
- }
-
- // We need to test groupingChar and decimalChar separately from groupingSet and decimalSet, if the sets are even initialized.
- // If sawDecimal is TRUE, only consider sawDecimalChar and NOT decimalSet
- // If a character matches decimalSet, don't consider it to be a member of the groupingSet.
-
- // We have to track digitCount ourselves, because digits.fCount will
- // pin when the maximum allowable digits is reached.
- int32_t digitCount = 0;
- int32_t integerDigitCount = 0;
-
- for (; position < textLength; )
- {
- UChar32 ch = text.char32At(position);
-
- /* We recognize all digit ranges, not only the Latin digit range
- * '0'..'9'. We do so by using the Character.digit() method,
- * which converts a valid Unicode digit to the range 0..9.
- *
- * The character 'ch' may be a digit. If so, place its value
- * from 0 to 9 in 'digit'. First try using the locale digit,
- * which may or MAY NOT be a standard Unicode digit range. If
- * this fails, try using the standard Unicode digit ranges by
- * calling Character.digit(). If this also fails, digit will
- * have a value outside the range 0..9.
- */
- digit = ch - zero;
- if (digit < 0 || digit > 9)
- {
- digit = u_charDigitValue(ch);
- }
-
- // As a last resort, look through the localized digits if the zero digit
- // is not a "standard" Unicode digit.
- if ( (digit < 0 || digit > 9) && u_charDigitValue(zero) != 0) {
- digit = 0;
- // Already check above (digit = ch - zero) for ch==zero; the only check we need to do here is:
- // if \u3007 is treated as 0 for parsing, \u96F6 should be too. Otherwise check for nonzero digits.
- if ( zero!=0x3007 || ch!=0x96F6 ) {
- for (digit = 1 ; digit < 10 ; digit++ ) {
- if ( getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)(DecimalFormatSymbols::kOneDigitSymbol+digit-1)).char32At(0) == ch ) {
- break;
- }
- }
- }
- }
-
- if (digit >= 0 && digit <= 9)
- {
- if (strictParse && backup != -1) {
- // comma followed by digit, so group before comma is a
- // secondary group. If there was a group separator
- // before that, the group must == the secondary group
- // length, else it can be <= the the secondary group
- // length.
- if ((lastGroup != -1 && backup - lastGroup - 1 != gs2) ||
- (lastGroup == -1 && position - digitStart - 1 > gs2)) {
- strictFail = TRUE;
- break;
- }
-
- lastGroup = backup;
- }
-
- // Cancel out backup setting (see grouping handler below)
- backup = -1;
- sawDigit = TRUE;
-
- // Note: this will append leading zeros
- parsedNum.append((char)(digit + '0'), err);
-
- // count any digit that's not a leading zero
- if (digit > 0 || digitCount > 0 || sawDecimal) {
- digitCount += 1;
-
- // count any integer digit that's not a leading zero
- if (! sawDecimal) {
- integerDigitCount += 1;
- }
- }
-
- position += U16_LENGTH(ch);
- }
- else if (groupingStringLength > 0 &&
- matchGrouping(groupingChar, sawGrouping, sawGroupingChar, groupingSet,
- decimalChar, decimalSet,
- ch) && groupingUsed)
- {
- if (sawDecimal) {
- break;
- }
-
- if (strictParse) {
- if ( (!sawDigit && groupingSet!=NULL && u_isWhitespace(ch)) || backup != -1 ) {
- // We differ from the ICU4J code by allowing a leading group sep in strict mode (for
- // backward compatibility) as long as it is not one of the breaking whitespace characters
- // that is only treated as a group separator because of the equivalence set. If we get
- // here it is because the leading sep was such a breaking space, or there were multiple
- // group separators in a row. Note that the DecimalFormat documentation says
- // "During parsing, grouping separators are ignored" and that was for strict parsing,
- // so we may need to further revisit this strictParse restriction to ensure compatibility.
- // Also note: u_isWhitespace is true for all Zs/Zl/Zp except the no-break ones: 00A0,2007,202F.
- // In CLDR, all locales that have space as a group separator use 00A0 (NBSP).
- strictFail = TRUE;
- break;
- }
- }
-
- // Ignore grouping characters, if we are using them, but require
- // that they be followed by a digit. Otherwise we backup and
- // reprocess them.
- backup = position;
- position += groupingStringLength;
- sawGrouping=TRUE;
- // Once we see a grouping character, we only accept that grouping character from then on.
- sawGroupingChar=ch;
- }
- else if (matchDecimal(decimalChar,sawDecimal,sawDecimalChar, decimalSet, ch))
- {
- if (strictParse) {
- if (backup != -1 ||
- (lastGroup != -1 && position - lastGroup != fGroupingSize + 1)) {
- strictFail = TRUE;
- break;
- }
- }
-
- // If we're only parsing integers, or if we ALREADY saw the
- // decimal, then don't parse this one.
- if (isParseIntegerOnly() || sawDecimal) {
- break;
- }
-
- parsedNum.append('.', err);
- position += decimalStringLength;
- sawDecimal = TRUE;
- // Once we see a decimal character, we only accept that decimal character from then on.
- sawDecimalChar=ch;
- // decimalSet is considered to consist of (ch,ch)
- }
- else {
-
- if(!fBoolFlags.contains(UNUM_PARSE_NO_EXPONENT) || // don't parse if this is set unless..
- isScientificNotation()) { // .. it's an exponent format - ignore setting and parse anyways
- const UnicodeString *tmp;
- tmp = &getConstSymbol(DecimalFormatSymbols::kExponentialSymbol);
- // TODO: CASE
- if (!text.caseCompare(position, tmp->length(), *tmp, U_FOLD_CASE_DEFAULT)) // error code is set below if !sawDigit
- {
- // Parse sign, if present
- int32_t pos = position + tmp->length();
- char exponentSign = '+';
-
- if (pos < textLength)
- {
- tmp = &getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
- if (!text.compare(pos, tmp->length(), *tmp))
- {
- pos += tmp->length();
- }
- else {
- tmp = &getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
- if (!text.compare(pos, tmp->length(), *tmp))
- {
- exponentSign = '-';
- pos += tmp->length();
- }
- }
- }
-
- UBool sawExponentDigit = FALSE;
- while (pos < textLength) {
- ch = text[(int32_t)pos];
- digit = ch - zero;
-
- if (digit < 0 || digit > 9) {
- digit = u_charDigitValue(ch);
- }
- if (0 <= digit && digit <= 9) {
- if (!sawExponentDigit) {
- parsedNum.append('E', err);
- parsedNum.append(exponentSign, err);
- sawExponentDigit = TRUE;
- }
- ++pos;
- parsedNum.append((char)(digit + '0'), err);
- } else {
- break;
- }
- }
-
- if (sawExponentDigit) {
- position = pos; // Advance past the exponent
- }
-
- break; // Whether we fail or succeed, we exit this loop
- } else {
- break;
- }
- } else { // not parsing exponent
- break;
- }
- }
- }
-
- if (backup != -1)
- {
- position = backup;
- }
-
- if (strictParse && !sawDecimal) {
- if (lastGroup != -1 && position - lastGroup != fGroupingSize + 1) {
- strictFail = TRUE;
- }
- }
-
- if (strictFail) {
- // only set with strictParse and a grouping separator error
-
- parsePosition.setIndex(oldStart);
- parsePosition.setErrorIndex(position);
- debug("strictFail!");
- return FALSE;
- }
-
- // If there was no decimal point we have an integer
-
- // If none of the text string was recognized. For example, parse
- // "x" with pattern "#0.00" (return index and error index both 0)
- // parse "$" with pattern "$#0.00". (return index 0 and error index
- // 1).
- if (!sawDigit && digitCount == 0) {
-#ifdef FMT_DEBUG
- debug("none of text rec");
- printf("position=%d\n",position);
-#endif
- parsePosition.setIndex(oldStart);
- parsePosition.setErrorIndex(oldStart);
- return FALSE;
- }
- }
-
- // Match padding before suffix
- if (fFormatWidth > 0 && fPadPosition == kPadBeforeSuffix) {
- position = skipPadding(text, position);
- }
-
- int32_t posSuffixMatch = -1, negSuffixMatch = -1;
-
- // Match positive and negative suffixes; prefer longest match.
- if (posMatch >= 0 || (!strictParse && negMatch < 0)) {
- posSuffixMatch = compareAffix(text, position, FALSE, FALSE, posSuffix, complexCurrencyParsing, type, currency);
- }
- if (negMatch >= 0) {
- negSuffixMatch = compareAffix(text, position, TRUE, FALSE, negSuffix, complexCurrencyParsing, type, currency);
- }
- if (posSuffixMatch >= 0 && negSuffixMatch >= 0) {
- if (posSuffixMatch > negSuffixMatch) {
- negSuffixMatch = -1;
- } else if (negSuffixMatch > posSuffixMatch) {
- posSuffixMatch = -1;
- }
- }
-
- // Fail if neither or both
- if (strictParse && ((posSuffixMatch >= 0) == (negSuffixMatch >= 0))) {
- parsePosition.setErrorIndex(position);
- debug("neither or both");
- return FALSE;
- }
-
- position += (posSuffixMatch >= 0 ? posSuffixMatch : (negSuffixMatch >= 0 ? negSuffixMatch : 0));
-
- // Match padding before suffix
- if (fFormatWidth > 0 && fPadPosition == kPadAfterSuffix) {
- position = skipPadding(text, position);
- }
-
- parsePosition.setIndex(position);
-
- parsedNum.data()[0] = (posSuffixMatch >= 0 || (!strictParse && negMatch < 0 && negSuffixMatch < 0)) ? '+' : '-';
-#ifdef FMT_DEBUG
-printf("PP -> %d, SLOW = [%s]! pp=%d, os=%d, err=%s\n", position, parsedNum.data(), parsePosition.getIndex(),oldStart,u_errorName(err));
-#endif
- } /* end SLOW parse */
- if(parsePosition.getIndex() == oldStart)
- {
-#ifdef FMT_DEBUG
- printf(" PP didnt move, err\n");
-#endif
- parsePosition.setErrorIndex(position);
- return FALSE;
- }
-#if UCONFIG_HAVE_PARSEALLINPUT
- else if (fParseAllInput==UNUM_YES&&parsePosition.getIndex()!=textLength)
- {
-#ifdef FMT_DEBUG
- printf(" PP didnt consume all (UNUM_YES), err\n");
-#endif
- parsePosition.setErrorIndex(position);
- return FALSE;
- }
-#endif
- // uint32_t bits = (fastParseOk?kFastpathOk:0) |
- // (fastParseHadDecimal?0:kNoDecimal);
- //printf("FPOK=%d, FPHD=%d, bits=%08X\n", fastParseOk, fastParseHadDecimal, bits);
- digits.set(parsedNum.toStringPiece(),
- err,
- 0//bits
- );
-
- if (U_FAILURE(err)) {
-#ifdef FMT_DEBUG
- printf(" err setting %s\n", u_errorName(err));
-#endif
- parsePosition.setErrorIndex(position);
- return FALSE;
- }
- return TRUE;
-}
-
-/**
- * Starting at position, advance past a run of pad characters, if any.
- * Return the index of the first character after position that is not a pad
- * character. Result is >= position.
- */
-int32_t DecimalFormat::skipPadding(const UnicodeString& text, int32_t position) const {
- int32_t padLen = U16_LENGTH(fPad);
- while (position < text.length() &&
- text.char32At(position) == fPad) {
- position += padLen;
- }
- return position;
-}
-
-/**
- * Return the length matched by the given affix, or -1 if none.
- * Runs of white space in the affix, match runs of white space in
- * the input. Pattern white space and input white space are
- * determined differently; see code.
- * @param text input text
- * @param pos offset into input at which to begin matching
- * @param isNegative
- * @param isPrefix
- * @param affixPat affix pattern used for currency affix comparison.
- * @param complexCurrencyParsing whether it is currency parsing or not
- * @param type the currency type to parse against, LONG_NAME only or not.
- * @param currency return value for parsed currency, for generic
- * currency parsing mode, or null for normal parsing. In generic
- * currency parsing mode, any currency is parsed, not just the
- * currency that this formatter is set to.
- * @return length of input that matches, or -1 if match failure
- */
-int32_t DecimalFormat::compareAffix(const UnicodeString& text,
- int32_t pos,
- UBool isNegative,
- UBool isPrefix,
- const UnicodeString* affixPat,
- UBool complexCurrencyParsing,
- int8_t type,
- UChar* currency) const
-{
- const UnicodeString *patternToCompare;
- if (fCurrencyChoice != NULL || currency != NULL ||
- (fCurrencySignCount != fgCurrencySignCountZero && complexCurrencyParsing)) {
-
- if (affixPat != NULL) {
- return compareComplexAffix(*affixPat, text, pos, type, currency);
- }
- }
-
- if (isNegative) {
- if (isPrefix) {
- patternToCompare = &fNegativePrefix;
- }
- else {
- patternToCompare = &fNegativeSuffix;
- }
- }
- else {
- if (isPrefix) {
- patternToCompare = &fPositivePrefix;
- }
- else {
- patternToCompare = &fPositiveSuffix;
- }
- }
- return compareSimpleAffix(*patternToCompare, text, pos, isLenient());
-}
-
-UBool DecimalFormat::equalWithSignCompatibility(UChar32 lhs, UChar32 rhs) const {
- if (lhs == rhs) {
- return TRUE;
- }
- U_ASSERT(fStaticSets != NULL); // should already be loaded
- const UnicodeSet *minusSigns = fStaticSets->fMinusSigns;
- const UnicodeSet *plusSigns = fStaticSets->fPlusSigns;
- return (minusSigns->contains(lhs) && minusSigns->contains(rhs)) ||
- (plusSigns->contains(lhs) && plusSigns->contains(rhs));
-}
-
-// check for LRM 0x200E, RLM 0x200F, ALM 0x061C
-#define IS_BIDI_MARK(c) (c==0x200E || c==0x200F || c==0x061C)
-
-#define TRIM_BUFLEN 32
-UnicodeString& DecimalFormat::trimMarksFromAffix(const UnicodeString& affix, UnicodeString& trimmedAffix) {
- UChar trimBuf[TRIM_BUFLEN];
- int32_t affixLen = affix.length();
- int32_t affixPos, trimLen = 0;
-
- for (affixPos = 0; affixPos < affixLen; affixPos++) {
- UChar c = affix.charAt(affixPos);
- if (!IS_BIDI_MARK(c)) {
- if (trimLen < TRIM_BUFLEN) {
- trimBuf[trimLen++] = c;
- } else {
- trimLen = 0;
- break;
- }
- }
- }
- return (trimLen > 0)? trimmedAffix.setTo(trimBuf, trimLen): trimmedAffix.setTo(affix);
-}
-
-/**
- * Return the length matched by the given affix, or -1 if none.
- * Runs of white space in the affix, match runs of white space in
- * the input. Pattern white space and input white space are
- * determined differently; see code.
- * @param affix pattern string, taken as a literal
- * @param input input text
- * @param pos offset into input at which to begin matching
- * @return length of input that matches, or -1 if match failure
- */
-int32_t DecimalFormat::compareSimpleAffix(const UnicodeString& affix,
- const UnicodeString& input,
- int32_t pos,
- UBool lenient) const {
- int32_t start = pos;
- UnicodeString trimmedAffix;
- // For more efficiency we should keep lazily-created trimmed affixes around in
- // instance variables instead of trimming each time they are used (the next step)
- trimMarksFromAffix(affix, trimmedAffix);
- UChar32 affixChar = trimmedAffix.char32At(0);
- int32_t affixLength = trimmedAffix.length();
- int32_t inputLength = input.length();
- int32_t affixCharLength = U16_LENGTH(affixChar);
- UnicodeSet *affixSet;
- UErrorCode status = U_ZERO_ERROR;
-
- U_ASSERT(fStaticSets != NULL); // should already be loaded
-
- if (U_FAILURE(status)) {
- return -1;
- }
- if (!lenient) {
- affixSet = fStaticSets->fStrictDashEquivalents;
-
- // If the trimmedAffix is exactly one character long and that character
- // is in the dash set and the very next input character is also
- // in the dash set, return a match.
- if (affixCharLength == affixLength && affixSet->contains(affixChar)) {
- UChar32 ic = input.char32At(pos);
- if (affixSet->contains(ic)) {
- pos += U16_LENGTH(ic);
- pos = skipBidiMarks(input, pos); // skip any trailing bidi marks
- return pos - start;
- }
- }
-
- for (int32_t i = 0; i < affixLength; ) {
- UChar32 c = trimmedAffix.char32At(i);
- int32_t len = U16_LENGTH(c);
- if (PatternProps::isWhiteSpace(c)) {
- // We may have a pattern like: \u200F \u0020
- // and input text like: \u200F \u0020
- // Note that U+200F and U+0020 are Pattern_White_Space but only
- // U+0020 is UWhiteSpace. So we have to first do a direct
- // match of the run of Pattern_White_Space in the pattern,
- // then match any extra characters.
- UBool literalMatch = FALSE;
- while (pos < inputLength) {
- UChar32 ic = input.char32At(pos);
- if (ic == c) {
- literalMatch = TRUE;
- i += len;
- pos += len;
- if (i == affixLength) {
- break;
- }
- c = trimmedAffix.char32At(i);
- len = U16_LENGTH(c);
- if (!PatternProps::isWhiteSpace(c)) {
- break;
- }
- } else if (IS_BIDI_MARK(ic)) {
- pos ++; // just skip over this input text
- } else {
- break;
- }
- }
-
- // Advance over run in pattern
- i = skipPatternWhiteSpace(trimmedAffix, i);
-
- // Advance over run in input text
- // Must see at least one white space char in input,
- // unless we've already matched some characters literally.
- int32_t s = pos;
- pos = skipUWhiteSpace(input, pos);
- if (pos == s && !literalMatch) {
- return -1;
- }
-
- // If we skip UWhiteSpace in the input text, we need to skip it in the pattern.
- // Otherwise, the previous lines may have skipped over text (such as U+00A0) that
- // is also in the trimmedAffix.
- i = skipUWhiteSpace(trimmedAffix, i);
- } else {
- UBool match = FALSE;
- while (pos < inputLength) {
- UChar32 ic = input.char32At(pos);
- if (!match && ic == c) {
- i += len;
- pos += len;
- match = TRUE;
- } else if (IS_BIDI_MARK(ic)) {
- pos++; // just skip over this input text
- } else {
- break;
- }
- }
- if (!match) {
- return -1;
- }
- }
- }
- } else {
- UBool match = FALSE;
-
- affixSet = fStaticSets->fDashEquivalents;
-
- if (affixCharLength == affixLength && affixSet->contains(affixChar)) {
- pos = skipUWhiteSpaceAndMarks(input, pos);
- UChar32 ic = input.char32At(pos);
-
- if (affixSet->contains(ic)) {
- pos += U16_LENGTH(ic);
- pos = skipBidiMarks(input, pos);
- return pos - start;
- }
- }
-
- for (int32_t i = 0; i < affixLength; )
- {
- //i = skipRuleWhiteSpace(trimmedAffix, i);
- i = skipUWhiteSpace(trimmedAffix, i);
- pos = skipUWhiteSpaceAndMarks(input, pos);
-
- if (i >= affixLength || pos >= inputLength) {
- break;
- }
-
- UChar32 c = trimmedAffix.char32At(i);
- UChar32 ic = input.char32At(pos);
-
- if (!equalWithSignCompatibility(ic, c)) {
- return -1;
- }
-
- match = TRUE;
- i += U16_LENGTH(c);
- pos += U16_LENGTH(ic);
- pos = skipBidiMarks(input, pos);
- }
-
- if (affixLength > 0 && ! match) {
- return -1;
- }