/*
*******************************************************************************
-* Copyright (C) 1997-2009, International Business Machines Corporation
+* Copyright (C) 1997-2012, International Business Machines Corporation
* and others. All Rights Reserved.
*******************************************************************************
*/
+#include <typeinfo> // for 'typeid' to work
+
#include "unicode/rbnf.h"
#if U_HAVE_RBNF
#include "cmemory.h"
#include "cstring.h"
-#include "util.h"
+#include "patternprops.h"
+#include "uresimp.h"
// debugging
// #define DEBUG
*/
class LocalizationInfo : public UMemory {
protected:
- virtual ~LocalizationInfo() {};
+ virtual ~LocalizationInfo();
uint32_t refcount;
public:
// static UClassID getStaticClassID(void);
};
+LocalizationInfo::~LocalizationInfo() {}
+
//UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(LocalizationInfo)
// if both strings are NULL, this returns TRUE
void inc(void) { ++p; ch = 0xffff; }
UBool checkInc(UChar c) { if (p < e && (ch == c || *p == c)) { inc(); return TRUE; } return FALSE; }
UBool check(UChar c) { return p < e && (ch == c || *p == c); }
- void skipWhitespace(void) { while (p < e && uprv_isRuleWhiteSpace(ch != 0xffff ? ch : *p)) inc();}
+ void skipWhitespace(void) { while (p < e && PatternProps::isWhiteSpace(ch != 0xffff ? ch : *p)) inc();}
UBool inList(UChar c, const UChar* list) const {
- if (*list == SPACE && uprv_isRuleWhiteSpace(c)) return TRUE;
+ if (*list == SPACE && PatternProps::isWhiteSpace(c)) return TRUE;
while (*list && *list != c) ++list; return *list == c;
}
void parseError(const char* msg);
const UnicodeString& locs,
const Locale& alocale, UParseError& perror, UErrorCode& status)
: ruleSets(NULL)
+ , ruleSetDescriptions(NULL)
+ , numRuleSets(0)
, defaultRuleSet(NULL)
, locale(alocale)
, collator(NULL)
const UnicodeString& locs,
UParseError& perror, UErrorCode& status)
: ruleSets(NULL)
+ , ruleSetDescriptions(NULL)
+ , numRuleSets(0)
, defaultRuleSet(NULL)
, locale(Locale::getDefault())
, collator(NULL)
LocalizationInfo* info,
const Locale& alocale, UParseError& perror, UErrorCode& status)
: ruleSets(NULL)
+ , ruleSetDescriptions(NULL)
+ , numRuleSets(0)
, defaultRuleSet(NULL)
, locale(alocale)
, collator(NULL)
UParseError& perror,
UErrorCode& status)
: ruleSets(NULL)
+ , ruleSetDescriptions(NULL)
+ , numRuleSets(0)
, defaultRuleSet(NULL)
, locale(Locale::getDefault())
, collator(NULL)
UParseError& perror,
UErrorCode& status)
: ruleSets(NULL)
+ , ruleSetDescriptions(NULL)
+ , numRuleSets(0)
, defaultRuleSet(NULL)
, locale(aLocale)
, collator(NULL)
RuleBasedNumberFormat::RuleBasedNumberFormat(URBNFRuleSetTag tag, const Locale& alocale, UErrorCode& status)
: ruleSets(NULL)
+ , ruleSetDescriptions(NULL)
+ , numRuleSets(0)
, defaultRuleSet(NULL)
, locale(alocale)
, collator(NULL)
return;
}
+ const char* rules_tag = "RBNFRules";
const char* fmt_tag = "";
switch (tag) {
case URBNF_SPELLOUT: fmt_tag = "SpelloutRules"; break;
case URBNF_ORDINAL: fmt_tag = "OrdinalRules"; break;
case URBNF_DURATION: fmt_tag = "DurationRules"; break;
+ case URBNF_NUMBERING_SYSTEM: fmt_tag = "NumberingSystemRules"; break;
default: status = U_ILLEGAL_ARGUMENT_ERROR; return;
}
// TODO: read localization info from resource
LocalizationInfo* locinfo = NULL;
- int32_t len = 0;
UResourceBundle* nfrb = ures_open(U_ICUDATA_RBNF, locale.getName(), &status);
if (U_SUCCESS(status)) {
setLocaleIDs(ures_getLocaleByType(nfrb, ULOC_VALID_LOCALE, &status),
ures_getLocaleByType(nfrb, ULOC_ACTUAL_LOCALE, &status));
- const UChar* description = ures_getStringByKey(nfrb, fmt_tag, &len, &status);
- UnicodeString desc(description, len);
+
+ UResourceBundle* rbnfRules = ures_getByKeyWithFallback(nfrb, rules_tag, NULL, &status);
+ if (U_FAILURE(status)) {
+ ures_close(nfrb);
+ }
+ UResourceBundle* ruleSets = ures_getByKeyWithFallback(rbnfRules, fmt_tag, NULL, &status);
+ if (U_FAILURE(status)) {
+ ures_close(rbnfRules);
+ ures_close(nfrb);
+ return;
+ }
+
+ UnicodeString desc;
+ while (ures_hasNext(ruleSets)) {
+ desc.append(ures_getNextUnicodeString(ruleSets,NULL,&status));
+ }
UParseError perror;
+
init (desc, locinfo, perror, status);
+
+ ures_close(ruleSets);
+ ures_close(rbnfRules);
}
ures_close(nfrb);
}
RuleBasedNumberFormat::RuleBasedNumberFormat(const RuleBasedNumberFormat& rhs)
: NumberFormat(rhs)
, ruleSets(NULL)
+ , ruleSetDescriptions(NULL)
+ , numRuleSets(0)
, defaultRuleSet(NULL)
, locale(rhs.locale)
, collator(NULL)
return TRUE;
}
- if (other.getDynamicClassID() == getStaticClassID()) {
+ if (typeid(*this) == typeid(other)) {
const RuleBasedNumberFormat& rhs = (const RuleBasedNumberFormat&)other;
if (locale == rhs.locale &&
lenient == rhs.lenient &&
UnicodeString& toAppendTo,
FieldPosition& /* pos */) const
{
- if (defaultRuleSet) defaultRuleSet->format(number, toAppendTo, toAppendTo.length());
+ // Special case for NaN; adapted from what DecimalFormat::_format( double number,...) does.
+ if (uprv_isNaN(number)) {
+ DecimalFormatSymbols* decFmtSyms = getDecimalFormatSymbols(); // RuleBasedNumberFormat internal
+ if (decFmtSyms) {
+ toAppendTo += decFmtSyms->getConstSymbol(DecimalFormatSymbols::kNaNSymbol);
+ }
+ } else if (defaultRuleSet) {
+ defaultRuleSet->format(number, toAppendTo, toAppendTo.length());
+ }
return toAppendTo;
}
{
// return format((int64_t)number, ruleSetName, toAppendTo, pos, status);
if (U_SUCCESS(status)) {
- if (ruleSetName.indexOf(gPercentPercent) == 0) {
+ if (ruleSetName.indexOf(gPercentPercent, 2, 0) == 0) {
// throw new IllegalArgumentException("Can't use internal rule set");
status = U_ILLEGAL_ARGUMENT_ERROR;
} else {
UErrorCode& status) const
{
if (U_SUCCESS(status)) {
- if (ruleSetName.indexOf(gPercentPercent) == 0) {
+ if (ruleSetName.indexOf(gPercentPercent, 2, 0) == 0) {
// throw new IllegalArgumentException("Can't use internal rule set");
status = U_ILLEGAL_ARGUMENT_ERROR;
} else {
UErrorCode& status) const
{
if (U_SUCCESS(status)) {
- if (ruleSetName.indexOf(gPercentPercent) == 0) {
+ if (ruleSetName.indexOf(gPercentPercent, 2, 0) == 0) {
// throw new IllegalArgumentException("Can't use internal rule set");
status = U_ILLEGAL_ARGUMENT_ERROR;
} else {
for (NFRuleSet** p = ruleSets; *p; ++p) {
NFRuleSet *rp = *p;
- if (rp->isPublic()) {
+ if (rp->isPublic() && rp->isParseable()) {
ParsePosition working_pp(0);
Formattable working_result;
- rp->parse(workingText, working_pp, kMaxDouble, working_result);
+ rp->parse(workingText, working_pp, kMaxDouble, working_result, lenient);
if (working_pp.getIndex() > high_pp.getIndex()) {
high_pp = working_pp;
high_result = working_result;
return;
}
+ const UnicodeString spellout = UNICODE_STRING_SIMPLE("%spellout-numbering");
+ const UnicodeString ordinal = UNICODE_STRING_SIMPLE("%digits-ordinal");
+ const UnicodeString duration = UNICODE_STRING_SIMPLE("%duration");
+
NFRuleSet**p = &ruleSets[0];
while (*p) {
- ++p;
+ if ((*p)->isNamed(spellout) || (*p)->isNamed(ordinal) || (*p)->isNamed(duration)) {
+ defaultRuleSet = *p;
+ return;
+ } else {
+ ++p;
+ }
}
defaultRuleSet = *--p;
// is, pull them out into our temporary holding place for them,
// and delete them from the description before the real desciption-
// parsing code sees them
- int32_t lp = description.indexOf(gLenientParse);
+ int32_t lp = description.indexOf(gLenientParse, -1, 0);
if (lp != -1) {
// we've got to make sure we're not in the middle of a rule
// (where "%%lenient-parse" would actually get treated as
// locate the beginning and end of the actual collation
// rules (there may be whitespace between the name and
// the first token in the description)
- int lpEnd = description.indexOf(gSemiPercent, lp);
+ int lpEnd = description.indexOf(gSemiPercent, 2, lp);
if (lpEnd == -1) {
lpEnd = description.length() - 1;
}
int lpStart = lp + u_strlen(gLenientParse);
- while (uprv_isRuleWhiteSpace(description.charAt(lpStart))) {
+ while (PatternProps::isWhiteSpace(description.charAt(lpStart))) {
++lpStart;
}
// pre-flight parsing the description and count the number of
// rule sets (";%" marks the end of one rule set and the beginning
// of the next)
- int numRuleSets = 0;
- for (int32_t p = description.indexOf(gSemiPercent); p != -1; p = description.indexOf(gSemiPercent, p)) {
+ numRuleSets = 0;
+ for (int32_t p = description.indexOf(gSemiPercent, 2, 0); p != -1; p = description.indexOf(gSemiPercent, 2, p)) {
++numRuleSets;
++p;
}
status = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
- UnicodeString* ruleSetDescriptions = new UnicodeString[numRuleSets];
+
+ ruleSetDescriptions = new UnicodeString[numRuleSets];
if (ruleSetDescriptions == 0) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
{
int curRuleSet = 0;
int32_t start = 0;
- for (int32_t p = description.indexOf(gSemiPercent); p != -1; p = description.indexOf(gSemiPercent, start)) {
+ for (int32_t p = description.indexOf(gSemiPercent, 2, 0); p != -1; p = description.indexOf(gSemiPercent, 2, start)) {
ruleSetDescriptions[curRuleSet].setTo(description, start, p + 1 - start);
ruleSets[curRuleSet] = new NFRuleSet(ruleSetDescriptions, curRuleSet, status);
if (ruleSets[curRuleSet] == 0) {
status = U_MEMORY_ALLOCATION_ERROR;
- goto cleanup;
+ return;
}
++curRuleSet;
start = p + 1;
ruleSets[curRuleSet] = new NFRuleSet(ruleSetDescriptions, curRuleSet, status);
if (ruleSets[curRuleSet] == 0) {
status = U_MEMORY_ALLOCATION_ERROR;
- goto cleanup;
+ return;
}
}
} else {
defaultRuleSet = getDefaultRuleSet();
}
-
-cleanup:
- delete[] ruleSetDescriptions;
}
void
while (start != -1 && start < description.length()) {
// seek to the first non-whitespace character...
while (start < description.length()
- && uprv_isRuleWhiteSpace(description.charAt(start))) {
+ && PatternProps::isWhiteSpace(description.charAt(start))) {
++start;
}
ruleSets = NULL;
}
+ if (ruleSetDescriptions) {
+ delete [] ruleSetDescriptions;
+ }
+
#if !UCONFIG_NO_COLLATION
delete collator;
#endif
UErrorCode status = U_ZERO_ERROR;
Collator* temp = Collator::createInstance(locale, status);
- if (U_SUCCESS(status) &&
- temp->getDynamicClassID() == RuleBasedCollator::getStaticClassID()) {
-
- RuleBasedCollator* newCollator = (RuleBasedCollator*)temp;
+ RuleBasedCollator* newCollator;
+ if (U_SUCCESS(status) && (newCollator = dynamic_cast<RuleBasedCollator*>(temp)) != NULL) {
if (lenientParseRules) {
UnicodeString rules(newCollator->getRules());
rules.append(*lenientParseRules);
return decimalFormatSymbols;
}
+// De-owning the current localized symbols and adopt the new symbols.
+void
+RuleBasedNumberFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt)
+{
+ if (symbolsToAdopt == NULL) {
+ return; // do not allow caller to set decimalFormatSymbols to NULL
+ }
+
+ if (decimalFormatSymbols != NULL) {
+ delete decimalFormatSymbols;
+ }
+
+ decimalFormatSymbols = symbolsToAdopt;
+
+ {
+ // Apply the new decimalFormatSymbols by reparsing the rulesets
+ UErrorCode status = U_ZERO_ERROR;
+
+ for (int32_t i = 0; i < numRuleSets; i++) {
+ ruleSets[i]->parseRules(ruleSetDescriptions[i], this, status);
+ }
+ }
+}
+
+// Setting the symbols is equlivalent to adopting a newly created localized symbols.
+void
+RuleBasedNumberFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols)
+{
+ adoptDecimalFormatSymbols(new DecimalFormatSymbols(symbols));
+}
+
U_NAMESPACE_END
/* U_HAVE_RBNF */