X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/374ca955a76ecab1204ca8bfa63ff9238d998416..f59164e3d128c7675a4d3934206346a3384e53a5:/icuSources/i18n/nfrs.cpp diff --git a/icuSources/i18n/nfrs.cpp b/icuSources/i18n/nfrs.cpp index a066614f..e2c41f2b 100644 --- a/icuSources/i18n/nfrs.cpp +++ b/icuSources/i18n/nfrs.cpp @@ -1,6 +1,6 @@ /* ****************************************************************************** -* Copyright (C) 1997-2004, International Business Machines +* Copyright (C) 1997-2015, International Business Machines * Corporation and others. All Rights Reserved. ****************************************************************************** * file name: nfrs.cpp @@ -20,12 +20,27 @@ #include "unicode/uchar.h" #include "nfrule.h" #include "nfrlist.h" +#include "patternprops.h" #ifdef RBNF_DEBUG #include "cmemory.h" #endif -#include "util.h" +enum { + /** -x */ + NEGATIVE_RULE_INDEX = 0, + /** x.x */ + IMPROPER_FRACTION_RULE_INDEX = 1, + /** 0.x */ + PROPER_FRACTION_RULE_INDEX = 2, + /** x.0 */ + MASTER_RULE_INDEX = 3, + /** Inf */ + INFINITY_RULE_INDEX = 4, + /** NaN */ + NAN_RULE_INDEX = 5, + NON_NUMERICAL_RULE_LENGTH = 6 +}; U_NAMESPACE_BEGIN @@ -105,25 +120,27 @@ static const UChar gColon = 0x003a; static const UChar gSemicolon = 0x003b; static const UChar gLineFeed = 0x000a; -static const UChar gFourSpaces[] = -{ - 0x20, 0x20, 0x20, 0x20, 0 -}; /* " " */ static const UChar gPercentPercent[] = { 0x25, 0x25, 0 }; /* "%%" */ -NFRuleSet::NFRuleSet(UnicodeString* descriptions, int32_t index, UErrorCode& status) +static const UChar gNoparse[] = +{ + 0x40, 0x6E, 0x6F, 0x70, 0x61, 0x72, 0x73, 0x65, 0 +}; /* "@noparse" */ + +NFRuleSet::NFRuleSet(RuleBasedNumberFormat *_owner, UnicodeString* descriptions, int32_t index, UErrorCode& status) : name() , rules(0) - , negativeNumberRule(NULL) + , owner(_owner) + , fractionRules() , fIsFractionRuleSet(FALSE) , fIsPublic(FALSE) - , fRecursionCount(0) + , fIsParseable(TRUE) { - for (int i = 0; i < 3; ++i) { - fractionRules[i] = NULL; + for (int32_t i = 0; i < NON_NUMERICAL_RULE_LENGTH; ++i) { + nonNumericalRules[i] = NULL; } if (U_FAILURE(status)) { @@ -135,7 +152,7 @@ NFRuleSet::NFRuleSet(UnicodeString* descriptions, int32_t index, UErrorCode& sta if (description.length() == 0) { // throw new IllegalArgumentException("Empty rule set description"); status = U_PARSE_ERROR; - return; + return; } // if the description begins with a rule set name (the rule set @@ -149,7 +166,7 @@ NFRuleSet::NFRuleSet(UnicodeString* descriptions, int32_t index, UErrorCode& sta status = U_PARSE_ERROR; } else { name.setTo(description, 0, pos); - while (pos < description.length() && uprv_isRuleWhiteSpace(description.charAt(++pos))) { + while (pos < description.length() && PatternProps::isWhiteSpace(description.charAt(++pos))) { } description.remove(0, pos); } @@ -162,14 +179,19 @@ NFRuleSet::NFRuleSet(UnicodeString* descriptions, int32_t index, UErrorCode& sta status = U_PARSE_ERROR; } - fIsPublic = name.indexOf(gPercentPercent) != 0; + fIsPublic = name.indexOf(gPercentPercent, 2, 0) != 0; + + if ( name.endsWith(gNoparse,8) ) { + fIsParseable = FALSE; + name.truncate(name.length()-8); // remove the @noparse from the name + } // all of the other members of NFRuleSet are initialized // by parseRules() } void -NFRuleSet::parseRules(UnicodeString& description, const RuleBasedNumberFormat* owner, UErrorCode& status) +NFRuleSet::parseRules(UnicodeString& description, UErrorCode& status) { // start by creating a Vector whose elements are Strings containing // the descriptions of the rules (one rule per element). The rules @@ -180,6 +202,9 @@ NFRuleSet::parseRules(UnicodeString& description, const RuleBasedNumberFormat* o return; } + // ensure we are starting with an empty rule list + rules.deleteAll(); + // dlf - the original code kept a separate description array for no reason, // so I got rid of it. The loop was too complex so I simplified it. @@ -204,73 +229,103 @@ NFRuleSet::parseRules(UnicodeString& description, const RuleBasedNumberFormat* o // (this isn't a for loop because we might be deleting items from // the vector-- we want to make sure we only increment i when // we _didn't_ delete aything from the vector) - uint32_t i = 0; - while (i < rules.size()) { + int32_t rulesSize = rules.size(); + for (int32_t i = 0; i < rulesSize; i++) { NFRule* rule = rules[i]; + int64_t baseValue = rule->getBaseValue(); - switch (rule->getType()) { + if (baseValue == 0) { // if the rule's base value is 0, fill in a default // base value (this will be 1 plus the preceding // rule's base value for regular rule sets, and the // same as the preceding rule's base value in fraction // rule sets) - case NFRule::kNoBase: rule->setBaseValue(defaultBaseValue, status); - if (!isFractionRuleSet()) { - ++defaultBaseValue; - } - ++i; - break; - - // if it's the negative-number rule, copy it into its own - // data member and delete it from the list - case NFRule::kNegativeNumberRule: - negativeNumberRule = rules.remove(i); - break; - - // if it's the improper fraction rule, copy it into the - // correct element of fractionRules - case NFRule::kImproperFractionRule: - fractionRules[0] = rules.remove(i); - break; - - // if it's the proper fraction rule, copy it into the - // correct element of fractionRules - case NFRule::kProperFractionRule: - fractionRules[1] = rules.remove(i); - break; - - // if it's the master rule, copy it into the - // correct element of fractionRules - case NFRule::kMasterRule: - fractionRules[2] = rules.remove(i); - break; - + } + else { // if it's a regular rule that already knows its base value, // check to make sure the rules are in order, and update // the default base value for the next rule - default: - if (rule->getBaseValue() < defaultBaseValue) { + if (baseValue < defaultBaseValue) { // throw new IllegalArgumentException("Rules are not in order"); status = U_PARSE_ERROR; return; } - defaultBaseValue = rule->getBaseValue(); - if (!isFractionRuleSet()) { - ++defaultBaseValue; - } - ++i; - break; + defaultBaseValue = baseValue; } + if (!fIsFractionRuleSet) { + ++defaultBaseValue; + } + } +} + +/** + * Set one of the non-numerical rules. + * @param rule The rule to set. + */ +void NFRuleSet::setNonNumericalRule(NFRule *rule) { + int64_t baseValue = rule->getBaseValue(); + if (baseValue == NFRule::kNegativeNumberRule) { + delete nonNumericalRules[NEGATIVE_RULE_INDEX]; + nonNumericalRules[NEGATIVE_RULE_INDEX] = rule; + } + else if (baseValue == NFRule::kImproperFractionRule) { + setBestFractionRule(IMPROPER_FRACTION_RULE_INDEX, rule, TRUE); + } + else if (baseValue == NFRule::kProperFractionRule) { + setBestFractionRule(PROPER_FRACTION_RULE_INDEX, rule, TRUE); + } + else if (baseValue == NFRule::kMasterRule) { + setBestFractionRule(MASTER_RULE_INDEX, rule, TRUE); + } + else if (baseValue == NFRule::kInfinityRule) { + delete nonNumericalRules[INFINITY_RULE_INDEX]; + nonNumericalRules[INFINITY_RULE_INDEX] = rule; + } + else if (baseValue == NFRule::kNaNRule) { + delete nonNumericalRules[NAN_RULE_INDEX]; + nonNumericalRules[NAN_RULE_INDEX] = rule; + } +} + +/** + * Determine the best fraction rule to use. Rules matching the decimal point from + * DecimalFormatSymbols become the main set of rules to use. + * @param originalIndex The index into nonNumericalRules + * @param newRule The new rule to consider + * @param rememberRule Should the new rule be added to fractionRules. + */ +void NFRuleSet::setBestFractionRule(int32_t originalIndex, NFRule *newRule, UBool rememberRule) { + if (rememberRule) { + fractionRules.add(newRule); + } + NFRule *bestResult = nonNumericalRules[originalIndex]; + if (bestResult == NULL) { + nonNumericalRules[originalIndex] = newRule; + } + else { + // We have more than one. Which one is better? + const DecimalFormatSymbols *decimalFormatSymbols = owner->getDecimalFormatSymbols(); + if (decimalFormatSymbols->getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol).charAt(0) + == newRule->getDecimalPoint()) + { + nonNumericalRules[originalIndex] = newRule; + } + // else leave it alone } } NFRuleSet::~NFRuleSet() { - delete negativeNumberRule; - delete fractionRules[0]; - delete fractionRules[1]; - delete fractionRules[2]; + for (int i = 0; i < NON_NUMERICAL_RULE_LENGTH; i++) { + if (i != IMPROPER_FRACTION_RULE_INDEX + && i != PROPER_FRACTION_RULE_INDEX + && i != MASTER_RULE_INDEX) + { + delete nonNumericalRules[i]; + } + // else it will be deleted via NFRuleList fractionRules + } } static UBool @@ -291,12 +346,16 @@ NFRuleSet::operator==(const NFRuleSet& rhs) const { if (rules.size() == rhs.rules.size() && fIsFractionRuleSet == rhs.fIsFractionRuleSet && - name == rhs.name && - util_equalRules(negativeNumberRule, rhs.negativeNumberRule) && - util_equalRules(fractionRules[0], rhs.fractionRules[0]) && - util_equalRules(fractionRules[1], rhs.fractionRules[1]) && - util_equalRules(fractionRules[2], rhs.fractionRules[2])) { + name == rhs.name) { + // ...then compare the non-numerical rule lists... + for (int i = 0; i < NON_NUMERICAL_RULE_LENGTH; i++) { + if (!util_equalRules(nonNumericalRules[i], rhs.nonNumericalRules[i])) { + return FALSE; + } + } + + // ...then compare the rule lists... for (uint32_t i = 0; i < rules.size(); ++i) { if (*rules[i] != *rhs.rules[i]) { return FALSE; @@ -307,41 +366,62 @@ NFRuleSet::operator==(const NFRuleSet& rhs) const return FALSE; } -#define RECURSION_LIMIT 50 +void +NFRuleSet::setDecimalFormatSymbols(const DecimalFormatSymbols &newSymbols, UErrorCode& status) { + for (uint32_t i = 0; i < rules.size(); ++i) { + rules[i]->setDecimalFormatSymbols(newSymbols, status); + } + // Switch the fraction rules to mirror the DecimalFormatSymbols. + for (int32_t nonNumericalIdx = IMPROPER_FRACTION_RULE_INDEX; nonNumericalIdx <= MASTER_RULE_INDEX; nonNumericalIdx++) { + if (nonNumericalRules[nonNumericalIdx]) { + for (uint32_t fIdx = 0; fIdx < fractionRules.size(); fIdx++) { + NFRule *fractionRule = fractionRules[fIdx]; + if (nonNumericalRules[nonNumericalIdx]->getBaseValue() == fractionRule->getBaseValue()) { + setBestFractionRule(nonNumericalIdx, fractionRule, FALSE); + } + } + } + } + + for (uint32_t nnrIdx = 0; nnrIdx < NON_NUMERICAL_RULE_LENGTH; nnrIdx++) { + NFRule *rule = nonNumericalRules[nnrIdx]; + if (rule) { + rule->setDecimalFormatSymbols(newSymbols, status); + } + } +} + +#define RECURSION_LIMIT 64 void -NFRuleSet::format(int64_t number, UnicodeString& toAppendTo, int32_t pos) const +NFRuleSet::format(int64_t number, UnicodeString& toAppendTo, int32_t pos, int32_t recursionCount, UErrorCode& status) const { - NFRule *rule = findNormalRule(number); + if (recursionCount >= RECURSION_LIMIT) { + // stop recursion + status = U_INVALID_STATE_ERROR; + return; + } + const NFRule *rule = findNormalRule(number); if (rule) { // else error, but can't report it - NFRuleSet* ncThis = (NFRuleSet*)this; - if (ncThis->fRecursionCount++ >= RECURSION_LIMIT) { - // stop recursion - ncThis->fRecursionCount = 0; - } else { - rule->doFormat(number, toAppendTo, pos); - ncThis->fRecursionCount--; - } + rule->doFormat(number, toAppendTo, pos, ++recursionCount, status); } } void -NFRuleSet::format(double number, UnicodeString& toAppendTo, int32_t pos) const +NFRuleSet::format(double number, UnicodeString& toAppendTo, int32_t pos, int32_t recursionCount, UErrorCode& status) const { - NFRule *rule = findDoubleRule(number); + if (recursionCount >= RECURSION_LIMIT) { + // stop recursion + status = U_INVALID_STATE_ERROR; + return; + } + const NFRule *rule = findDoubleRule(number); if (rule) { // else error, but can't report it - NFRuleSet* ncThis = (NFRuleSet*)this; - if (ncThis->fRecursionCount++ >= RECURSION_LIMIT) { - // stop recursion - ncThis->fRecursionCount = 0; - } else { - rule->doFormat(number, toAppendTo, pos); - ncThis->fRecursionCount--; - } + rule->doFormat(number, toAppendTo, pos, ++recursionCount, status); } } -NFRule* +const NFRule* NFRuleSet::findDoubleRule(double number) const { // if this is a fraction rule set, use findFractionRuleSetRule() @@ -349,33 +429,49 @@ NFRuleSet::findDoubleRule(double number) const return findFractionRuleSetRule(number); } + if (uprv_isNaN(number)) { + const NFRule *rule = nonNumericalRules[NAN_RULE_INDEX]; + if (!rule) { + rule = owner->getDefaultNaNRule(); + } + return rule; + } + // if the number is negative, return the negative number rule // (if there isn't a negative-number rule, we pretend it's a // positive number) if (number < 0) { - if (negativeNumberRule) { - return negativeNumberRule; + if (nonNumericalRules[NEGATIVE_RULE_INDEX]) { + return nonNumericalRules[NEGATIVE_RULE_INDEX]; } else { number = -number; } } + if (uprv_isInfinite(number)) { + const NFRule *rule = nonNumericalRules[INFINITY_RULE_INDEX]; + if (!rule) { + rule = owner->getDefaultInfinityRule(); + } + return rule; + } + // if the number isn't an integer, we use one of the fraction rules... if (number != uprv_floor(number)) { // if the number is between 0 and 1, return the proper // fraction rule - if (number < 1 && fractionRules[1]) { - return fractionRules[1]; + if (number < 1 && nonNumericalRules[PROPER_FRACTION_RULE_INDEX]) { + return nonNumericalRules[PROPER_FRACTION_RULE_INDEX]; } // otherwise, return the improper fraction rule - else if (fractionRules[0]) { - return fractionRules[0]; + else if (nonNumericalRules[IMPROPER_FRACTION_RULE_INDEX]) { + return nonNumericalRules[IMPROPER_FRACTION_RULE_INDEX]; } } // if there's a master rule, use it to format the number - if (fractionRules[2]) { - return fractionRules[2]; + if (nonNumericalRules[MASTER_RULE_INDEX]) { + return nonNumericalRules[MASTER_RULE_INDEX]; } // and if we haven't yet returned a rule, use findNormalRule() @@ -384,7 +480,7 @@ NFRuleSet::findDoubleRule(double number) const return findNormalRule(r); } -NFRule * +const NFRule * NFRuleSet::findNormalRule(int64_t number) const { // if this is a fraction rule set, use findFractionRuleSetRule() @@ -397,8 +493,8 @@ NFRuleSet::findNormalRule(int64_t number) const // if the number is negative, return the negative-number rule // (if there isn't one, pretend the number is positive) if (number < 0) { - if (negativeNumberRule) { - return negativeNumberRule; + if (nonNumericalRules[NEGATIVE_RULE_INDEX]) { + return nonNumericalRules[NEGATIVE_RULE_INDEX]; } else { number = -number; } @@ -455,7 +551,7 @@ NFRuleSet::findNormalRule(int64_t number) const return result; } // else use the master rule - return fractionRules[2]; + return nonNumericalRules[MASTER_RULE_INDEX]; } /** @@ -473,7 +569,7 @@ NFRuleSet::findNormalRule(int64_t number) const * a number between 0 and 1) * @return The rule to use to format this number */ -NFRule* +const NFRule* NFRuleSet::findFractionRuleSetRule(double number) const { // the obvious way to do this (multiply the value being formatted @@ -572,15 +668,17 @@ NFRuleSet::findFractionRuleSetRule(double number) const static void dumpUS(FILE* f, const UnicodeString& us) { int len = us.length(); char* buf = (char *)uprv_malloc((len+1)*sizeof(char)); //new char[len+1]; - us.extract(0, len, buf); - buf[len] = 0; - fprintf(f, "%s", buf); - uprv_free(buf); //delete[] buf; + if (buf != NULL) { + us.extract(0, len, buf); + buf[len] = 0; + fprintf(f, "%s", buf); + uprv_free(buf); //delete[] buf; + } } #endif UBool -NFRuleSet::parse(const UnicodeString& text, ParsePosition& pos, double upperBound, Formattable& result) const +NFRuleSet::parse(const UnicodeString& text, ParsePosition& pos, double upperBound, Formattable& result, UBool lenient) const { // try matching each rule in the rule set against the text being // parsed. Whichever one matches the most characters is the one @@ -604,40 +702,16 @@ NFRuleSet::parse(const UnicodeString& text, ParsePosition& pos, double upperBoun fprintf(stderr, "'\n"); fprintf(stderr, " parse negative: %d\n", this, negativeNumberRule != 0); #endif - - // start by trying the negative number rule (if there is one) - if (negativeNumberRule) { - Formattable tempResult; -#ifdef RBNF_DEBUG - fprintf(stderr, " %x ub: %g\n", negativeNumberRule, upperBound); -#endif - UBool success = negativeNumberRule->doParse(text, workingPos, 0, upperBound, tempResult); -#ifdef RBNF_DEBUG - fprintf(stderr, " success: %d wpi: %d\n", success, workingPos.getIndex()); -#endif - if (success && workingPos.getIndex() > highWaterMark.getIndex()) { - result = tempResult; - highWaterMark = workingPos; - } - workingPos = pos; - } -#ifdef RBNF_DEBUG - fprintf(stderr, " continue fractional with text '"); - dumpUS(stderr, text); - fprintf(stderr, "' hwm: %d\n", highWaterMark.getIndex()); -#endif - // then try each of the fraction rules - { - for (int i = 0; i < 3; i++) { - if (fractionRules[i]) { - Formattable tempResult; - UBool success = fractionRules[i]->doParse(text, workingPos, 0, upperBound, tempResult); - if (success && (workingPos.getIndex() > highWaterMark.getIndex())) { - result = tempResult; - highWaterMark = workingPos; - } - workingPos = pos; + // Try each of the negative rules, fraction rules, infinity rules and NaN rules + for (int i = 0; i < NON_NUMERICAL_RULE_LENGTH; i++) { + if (nonNumericalRules[i]) { + Formattable tempResult; + UBool success = nonNumericalRules[i]->doParse(text, workingPos, 0, upperBound, tempResult, lenient || isDecimalFormatRuleParseable() ); + if (success && (workingPos.getIndex() > highWaterMark.getIndex())) { + result = tempResult; + highWaterMark = workingPos; } + workingPos = pos; } } #ifdef RBNF_DEBUG @@ -693,30 +767,37 @@ NFRuleSet::parse(const UnicodeString& text, ParsePosition& pos, double upperBoun void NFRuleSet::appendRules(UnicodeString& result) const { + uint32_t i; + // the rule set name goes first... result.append(name); result.append(gColon); result.append(gLineFeed); // followed by the regular rules... - for (uint32_t i = 0; i < rules.size(); i++) { - result.append(gFourSpaces); - rules[i]->appendRuleText(result); + for (i = 0; i < rules.size(); i++) { + rules[i]->_appendRuleText(result); result.append(gLineFeed); } // followed by the special rules (if they exist) - if (negativeNumberRule) { - result.append(gFourSpaces); - negativeNumberRule->appendRuleText(result); - result.append(gLineFeed); - } - - { - for (uint32_t i = 0; i < 3; ++i) { - if (fractionRules[i]) { - result.append(gFourSpaces); - fractionRules[i]->appendRuleText(result); + for (i = 0; i < NON_NUMERICAL_RULE_LENGTH; ++i) { + NFRule *rule = nonNumericalRules[i]; + if (nonNumericalRules[i]) { + if (rule->getBaseValue() == NFRule::kImproperFractionRule + || rule->getBaseValue() == NFRule::kProperFractionRule + || rule->getBaseValue() == NFRule::kMasterRule) + { + for (uint32_t fIdx = 0; fIdx < fractionRules.size(); fIdx++) { + NFRule *fractionRule = fractionRules[fIdx]; + if (fractionRule->getBaseValue() == rule->getBaseValue()) { + fractionRule->_appendRuleText(result); + result.append(gLineFeed); + } + } + } + else { + rule->_appendRuleText(result); result.append(gLineFeed); } } @@ -770,6 +851,7 @@ static const uint8_t asciiDigits[] = { static const UChar kUMinus = (UChar)0x002d; +#ifdef RBNF_DEBUG static const char kMinus = '-'; static const uint8_t digitInfo[] = { @@ -791,7 +873,6 @@ static const uint8_t digitInfo[] = { 0xa1u, 0xa2u, 0xa3u, 0, 0, 0, 0, 0, }; -#ifdef RBNF_DEBUG int64_t util64_atoi(const char* str, uint32_t radix) { if (radix > 36) { @@ -817,7 +898,6 @@ int64_t util64_atoi(const char* str, uint32_t radix) } return result; } -#endif int64_t util64_utoi(const UChar* str, uint32_t radix) { @@ -846,7 +926,6 @@ int64_t util64_utoi(const UChar* str, uint32_t radix) return result; } -#ifdef RBNF_DEBUG uint32_t util64_toa(int64_t w, char* buf, uint32_t len, uint32_t radix, UBool raw) { if (radix > 36) {