/*
*******************************************************************************
-* Copyright (C) 1997-2012, International Business Machines Corporation
+* Copyright (C) 1997-2014, International Business Machines Corporation
* and others. All Rights Reserved.
*******************************************************************************
*/
+#include "unicode/utypes.h"
#include "utypeinfo.h" // for 'typeid' to work
#include "unicode/rbnf.h"
#include "unicode/ustring.h"
#include "unicode/utf16.h"
#include "unicode/udata.h"
+#include "unicode/udisplaycontext.h"
+#include "unicode/brkiter.h"
#include "nfrs.h"
#include "cmemory.h"
#ifdef DEBUG
#define ERROR(msg) parseError(msg); return NULL;
+#define EXPLANATION_ARG explanationArg
#else
#define ERROR(msg) parseError(NULL); return NULL;
+#define EXPLANATION_ARG
#endif
return result;
}
-void
-LocDataParser::parseError(const char* /*str*/) {
+void LocDataParser::parseError(const char* EXPLANATION_ARG)
+{
if (!data) {
return;
}
pe.offset = (int32_t)(p - data);
#ifdef DEBUG
- fprintf(stderr, "%s at or near character %d: ", str, p-data);
+ fprintf(stderr, "%s at or near character %ld: ", EXPLANATION_ARG, p-data);
UnicodeString msg;
msg.append(start, p - start);
msg.append((UChar)0x002f); /* SOLIDUS/SLASH */
msg.append(p, limit-p);
- msg.append("'");
+ msg.append(UNICODE_STRING_SIMPLE("'"));
char buf[128];
int32_t len = msg.extract(0, msg.length(), buf, 128);
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
+ , capitalizationInfoSet(FALSE)
+ , capitalizationForUIListMenu(FALSE)
+ , capitalizationForStandAlone(FALSE)
+ , capitalizationBrkIter(NULL)
{
LocalizationInfo* locinfo = StringLocalizationInfo::create(locs, perror, status);
init(description, locinfo, perror, status);
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
+ , capitalizationInfoSet(FALSE)
+ , capitalizationForUIListMenu(FALSE)
+ , capitalizationForStandAlone(FALSE)
+ , capitalizationBrkIter(NULL)
{
LocalizationInfo* locinfo = StringLocalizationInfo::create(locs, perror, status);
init(description, locinfo, perror, status);
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
+ , capitalizationInfoSet(FALSE)
+ , capitalizationForUIListMenu(FALSE)
+ , capitalizationForStandAlone(FALSE)
+ , capitalizationBrkIter(NULL)
{
init(description, info, perror, status);
}
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
+ , capitalizationInfoSet(FALSE)
+ , capitalizationForUIListMenu(FALSE)
+ , capitalizationForStandAlone(FALSE)
+ , capitalizationBrkIter(NULL)
{
init(description, NULL, perror, status);
}
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
+ , capitalizationInfoSet(FALSE)
+ , capitalizationForUIListMenu(FALSE)
+ , capitalizationForStandAlone(FALSE)
+ , capitalizationBrkIter(NULL)
{
init(description, NULL, perror, status);
}
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
+ , capitalizationInfoSet(FALSE)
+ , capitalizationForUIListMenu(FALSE)
+ , capitalizationForStandAlone(FALSE)
+ , capitalizationBrkIter(NULL)
{
if (U_FAILURE(status)) {
return;
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
+ , capitalizationInfoSet(FALSE)
+ , capitalizationForUIListMenu(FALSE)
+ , capitalizationForStandAlone(FALSE)
+ , capitalizationBrkIter(NULL)
{
this->operator=(rhs);
}
RuleBasedNumberFormat&
RuleBasedNumberFormat::operator=(const RuleBasedNumberFormat& rhs)
{
+ if (this == &rhs) {
+ return *this;
+ }
+ NumberFormat::operator=(rhs);
UErrorCode status = U_ZERO_ERROR;
dispose();
locale = rhs.locale;
lenient = rhs.lenient;
- UnicodeString rules = rhs.getRules();
UParseError perror;
- init(rules, rhs.localizations ? rhs.localizations->ref() : NULL, perror, status);
+ init(rhs.originalDescription, rhs.localizations ? rhs.localizations->ref() : NULL, perror, status);
+ setDecimalFormatSymbols(*rhs.getDecimalFormatSymbols());
+ setDefaultRuleSet(rhs.getDefaultRuleSetName(), status);
+
+ capitalizationInfoSet = rhs.capitalizationInfoSet;
+ capitalizationForUIListMenu = rhs.capitalizationForUIListMenu;
+ capitalizationForStandAlone = rhs.capitalizationForStandAlone;
+#if !UCONFIG_NO_BREAK_ITERATION
+ capitalizationBrkIter = (rhs.capitalizationBrkIter!=NULL)? rhs.capitalizationBrkIter->clone(): NULL;
+#endif
return *this;
}
Format*
RuleBasedNumberFormat::clone(void) const
{
- RuleBasedNumberFormat * result = NULL;
- UnicodeString rules = getRules();
- UErrorCode status = U_ZERO_ERROR;
- UParseError perror;
- result = new RuleBasedNumberFormat(rules, localizations, locale, perror, status);
- /* test for NULL */
- if (result == 0) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return 0;
- }
- if (U_FAILURE(status)) {
- delete result;
- result = 0;
- } else {
- result->lenient = lenient;
- }
- return result;
+ return new RuleBasedNumberFormat(*this);
}
UBool
if (typeid(*this) == typeid(other)) {
const RuleBasedNumberFormat& rhs = (const RuleBasedNumberFormat&)other;
+ // test for capitalization info equality is adequately handled
+ // by the NumberFormat test for fCapitalizationContext equality;
+ // the info here is just derived from that.
if (locale == rhs.locale &&
lenient == rhs.lenient &&
(localizations == NULL
UnicodeString& toAppendTo,
FieldPosition& /* pos */) const
{
- if (defaultRuleSet) defaultRuleSet->format((int64_t)number, toAppendTo, toAppendTo.length());
+ if (defaultRuleSet) {
+ int32_t startPos = toAppendTo.length();
+ defaultRuleSet->format((int64_t)number, toAppendTo, toAppendTo.length());
+ adjustForCapitalizationContext(startPos, toAppendTo);
+ }
return toAppendTo;
}
UnicodeString& toAppendTo,
FieldPosition& /* pos */) const
{
- if (defaultRuleSet) defaultRuleSet->format(number, toAppendTo, toAppendTo.length());
+ if (defaultRuleSet) {
+ int32_t startPos = toAppendTo.length();
+ defaultRuleSet->format(number, toAppendTo, toAppendTo.length());
+ adjustForCapitalizationContext(startPos, toAppendTo);
+ }
return toAppendTo;
}
UnicodeString& toAppendTo,
FieldPosition& /* pos */) const
{
+ int32_t startPos = toAppendTo.length();
// Special case for NaN; adapted from what DecimalFormat::_format( double number,...) does.
if (uprv_isNaN(number)) {
DecimalFormatSymbols* decFmtSyms = getDecimalFormatSymbols(); // RuleBasedNumberFormat internal
} else if (defaultRuleSet) {
defaultRuleSet->format(number, toAppendTo, toAppendTo.length());
}
- return toAppendTo;
+ return adjustForCapitalizationContext(startPos, toAppendTo);
}
} else {
NFRuleSet *rs = findRuleSet(ruleSetName, status);
if (rs) {
+ int32_t startPos = toAppendTo.length();
rs->format((int64_t)number, toAppendTo, toAppendTo.length());
+ adjustForCapitalizationContext(startPos, toAppendTo);
}
}
}
} else {
NFRuleSet *rs = findRuleSet(ruleSetName, status);
if (rs) {
+ int32_t startPos = toAppendTo.length();
rs->format(number, toAppendTo, toAppendTo.length());
+ adjustForCapitalizationContext(startPos, toAppendTo);
}
}
}
}
-// make linker happy
-UnicodeString&
-RuleBasedNumberFormat::format(const Formattable& obj,
- UnicodeString& toAppendTo,
- FieldPosition& pos,
- UErrorCode& status) const
-{
- return NumberFormat::format(obj, toAppendTo, pos, status);
-}
-
UnicodeString&
RuleBasedNumberFormat::format(double number,
const UnicodeString& ruleSetName,
} else {
NFRuleSet *rs = findRuleSet(ruleSetName, status);
if (rs) {
+ int32_t startPos = toAppendTo.length();
rs->format(number, toAppendTo, toAppendTo.length());
+ adjustForCapitalizationContext(startPos, toAppendTo);
}
}
}
return toAppendTo;
}
+UnicodeString&
+RuleBasedNumberFormat::adjustForCapitalizationContext(int32_t startPos,
+ UnicodeString& currentResult) const
+{
+#if !UCONFIG_NO_BREAK_ITERATION
+ if (startPos==0 && currentResult.length() > 0) {
+ // capitalize currentResult according to context
+ UChar32 ch = currentResult.char32At(0);
+ UErrorCode status = U_ZERO_ERROR;
+ UDisplayContext capitalizationContext = getContext(UDISPCTX_TYPE_CAPITALIZATION, status);
+ if ( u_islower(ch) && U_SUCCESS(status) && capitalizationBrkIter!= NULL &&
+ ( capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
+ (capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && capitalizationForUIListMenu) ||
+ (capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && capitalizationForStandAlone)) ) {
+ // titlecase first word of currentResult, here use sentence iterator unlike current implementations
+ // in LocaleDisplayNamesImpl::adjustForUsageAndContext and RelativeDateFormat::format
+ currentResult.toTitle(capitalizationBrkIter, locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
+ }
+ }
+#endif
+ return currentResult;
+}
+
+
void
RuleBasedNumberFormat::parse(const UnicodeString& text,
Formattable& result,
} else {
defaultRuleSet = getDefaultRuleSet();
}
+ originalDescription = rules;
+}
+
+// override the NumberFormat implementation in order to
+// lazily initialize relevant items
+void
+RuleBasedNumberFormat::setContext(UDisplayContext value, UErrorCode& status)
+{
+ NumberFormat::setContext(value, status);
+ if (U_SUCCESS(status)) {
+ if (!capitalizationInfoSet &&
+ (value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE)) {
+ initCapitalizationContextInfo(locale);
+ capitalizationInfoSet = TRUE;
+ }
+#if !UCONFIG_NO_BREAK_ITERATION
+ if ( capitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
+ (value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && capitalizationForUIListMenu) ||
+ (value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && capitalizationForStandAlone)) ) {
+ UErrorCode status = U_ZERO_ERROR;
+ capitalizationBrkIter = BreakIterator::createSentenceInstance(locale, status);
+ if (U_FAILURE(status)) {
+ delete capitalizationBrkIter;
+ capitalizationBrkIter = NULL;
+ }
+ }
+#endif
+ }
+}
+
+void
+RuleBasedNumberFormat::initCapitalizationContextInfo(const Locale& thelocale)
+{
+#if !UCONFIG_NO_BREAK_ITERATION
+ const char * localeID = (thelocale != NULL)? thelocale.getBaseName(): NULL;
+ UErrorCode status = U_ZERO_ERROR;
+ UResourceBundle *rb = ures_open(NULL, localeID, &status);
+ rb = ures_getByKeyWithFallback(rb, "contextTransforms", rb, &status);
+ rb = ures_getByKeyWithFallback(rb, "number-spellout", rb, &status);
+ if (U_SUCCESS(status) && rb != NULL) {
+ int32_t len = 0;
+ const int32_t * intVector = ures_getIntVector(rb, &len, &status);
+ if (U_SUCCESS(status) && intVector != NULL && len >= 2) {
+ capitalizationForUIListMenu = intVector[0];
+ capitalizationForStandAlone = intVector[1];
+ }
+ }
+ ures_close(rb);
+#endif
}
void
delete lenientParseRules;
lenientParseRules = NULL;
+#if !UCONFIG_NO_BREAK_ITERATION
+ delete capitalizationBrkIter;
+ capitalizationBrkIter = NULL;
+#endif
+
if (localizations) localizations = localizations->unref();
}
* @return The collator to use for lenient parsing, or null if lenient parsing
* is turned off.
*/
-Collator*
+const RuleBasedCollator*
RuleBasedNumberFormat::getCollator() const
{
#if !UCONFIG_NO_COLLATION
return NULL;
}
- // lazy-evaulate the collator
+ // lazy-evaluate the collator
if (collator == NULL && lenient) {
// create a default collator based on the formatter's locale,
// then pull out that collator's rules, append any additional
newCollator = new RuleBasedCollator(rules, status);
// Exit if newCollator could not be created.
if (newCollator == NULL) {
- return NULL;
+ return NULL;
}
} else {
temp = NULL;