michael@0: /* michael@0: ******************************************************************************* michael@0: * Copyright (C) 2009-2013, International Business Machines Corporation and * michael@0: * others. All Rights Reserved. * michael@0: ******************************************************************************* michael@0: * michael@0: * This file contains the class DecimalFormatStaticSets michael@0: * michael@0: * DecimalFormatStaticSets holds the UnicodeSets that are needed for lenient michael@0: * parsing of decimal and group separators. michael@0: ******************************************************************************** michael@0: */ michael@0: michael@0: #include "unicode/utypes.h" michael@0: michael@0: #if !UCONFIG_NO_FORMATTING michael@0: michael@0: #include "unicode/unistr.h" michael@0: #include "unicode/uniset.h" michael@0: #include "unicode/uchar.h" michael@0: #include "cmemory.h" michael@0: #include "cstring.h" michael@0: #include "uassert.h" michael@0: #include "ucln_in.h" michael@0: #include "umutex.h" michael@0: michael@0: #include "decfmtst.h" michael@0: michael@0: U_NAMESPACE_BEGIN michael@0: michael@0: michael@0: //------------------------------------------------------------------------------ michael@0: // michael@0: // Unicode Set pattern strings for all of the required constant sets. michael@0: // Initialized with hex values for portability to EBCDIC based machines. michael@0: // Really ugly, but there's no good way to avoid it. michael@0: // michael@0: //------------------------------------------------------------------------------ michael@0: michael@0: static const UChar gDotEquivalentsPattern[] = { michael@0: // [ . \u2024 \u3002 \uFE12 \uFE52 \uFF0E \uFF61 ] michael@0: 0x005B, 0x002E, 0x2024, 0x3002, 0xFE12, 0xFE52, 0xFF0E, 0xFF61, 0x005D, 0x0000}; michael@0: michael@0: static const UChar gCommaEquivalentsPattern[] = { michael@0: // [ , \u060C \u066B \u3001 \uFE10 \uFE11 \uFE50 \uFE51 \uFF0C \uFF64 ] michael@0: 0x005B, 0x002C, 0x060C, 0x066B, 0x3001, 0xFE10, 0xFE11, 0xFE50, 0xFE51, 0xFF0C, 0xFF64, 0x005D, 0x0000}; michael@0: michael@0: static const UChar gOtherGroupingSeparatorsPattern[] = { michael@0: // [ \ SPACE ' NBSP \u066C \u2000 - \u200A \u2018 \u2019 \u202F \u205F \u3000 \uFF07 ] michael@0: 0x005B, 0x005C, 0x0020, 0x0027, 0x00A0, 0x066C, 0x2000, 0x002D, 0x200A, 0x2018, 0x2019, 0x202F, 0x205F, 0x3000, 0xFF07, 0x005D, 0x0000}; michael@0: michael@0: static const UChar gDashEquivalentsPattern[] = { michael@0: // [ \ - HYPHEN F_DASH N_DASH MINUS ] michael@0: 0x005B, 0x005C, 0x002D, 0x2010, 0x2012, 0x2013, 0x2212, 0x005D, 0x0000}; michael@0: michael@0: static const UChar gStrictDotEquivalentsPattern[] = { michael@0: // [ . \u2024 \uFE52 \uFF0E \uFF61 ] michael@0: 0x005B, 0x002E, 0x2024, 0xFE52, 0xFF0E, 0xFF61, 0x005D, 0x0000}; michael@0: michael@0: static const UChar gStrictCommaEquivalentsPattern[] = { michael@0: // [ , \u066B \uFE10 \uFE50 \uFF0C ] michael@0: 0x005B, 0x002C, 0x066B, 0xFE10, 0xFE50, 0xFF0C, 0x005D, 0x0000}; michael@0: michael@0: static const UChar gStrictOtherGroupingSeparatorsPattern[] = { michael@0: // [ \ SPACE ' NBSP \u066C \u2000 - \u200A \u2018 \u2019 \u202F \u205F \u3000 \uFF07 ] michael@0: 0x005B, 0x005C, 0x0020, 0x0027, 0x00A0, 0x066C, 0x2000, 0x002D, 0x200A, 0x2018, 0x2019, 0x202F, 0x205F, 0x3000, 0xFF07, 0x005D, 0x0000}; michael@0: michael@0: static const UChar gStrictDashEquivalentsPattern[] = { michael@0: // [ \ - MINUS ] michael@0: 0x005B, 0x005C, 0x002D, 0x2212, 0x005D, 0x0000}; michael@0: michael@0: static UChar32 gMinusSigns[] = { michael@0: 0x002D, michael@0: 0x207B, michael@0: 0x208B, michael@0: 0x2212, michael@0: 0x2796, michael@0: 0xFE63, michael@0: 0xFF0D}; michael@0: michael@0: static UChar32 gPlusSigns[] = { michael@0: 0x002B, michael@0: 0x207A, michael@0: 0x208A, michael@0: 0x2795, michael@0: 0xfB29, michael@0: 0xFE62, michael@0: 0xFF0B}; michael@0: michael@0: static void initUnicodeSet(const UChar32 *raw, int32_t len, UnicodeSet *s) { michael@0: for (int32_t i = 0; i < len; ++i) { michael@0: s->add(raw[i]); michael@0: } michael@0: } michael@0: michael@0: DecimalFormatStaticSets::DecimalFormatStaticSets(UErrorCode &status) michael@0: : fDotEquivalents(NULL), michael@0: fCommaEquivalents(NULL), michael@0: fOtherGroupingSeparators(NULL), michael@0: fDashEquivalents(NULL), michael@0: fStrictDotEquivalents(NULL), michael@0: fStrictCommaEquivalents(NULL), michael@0: fStrictOtherGroupingSeparators(NULL), michael@0: fStrictDashEquivalents(NULL), michael@0: fDefaultGroupingSeparators(NULL), michael@0: fStrictDefaultGroupingSeparators(NULL), michael@0: fMinusSigns(NULL), michael@0: fPlusSigns(NULL) michael@0: { michael@0: fDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gDotEquivalentsPattern, -1), status); michael@0: fCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gCommaEquivalentsPattern, -1), status); michael@0: fOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gOtherGroupingSeparatorsPattern, -1), status); michael@0: fDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gDashEquivalentsPattern, -1), status); michael@0: michael@0: fStrictDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDotEquivalentsPattern, -1), status); michael@0: fStrictCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictCommaEquivalentsPattern, -1), status); michael@0: fStrictOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gStrictOtherGroupingSeparatorsPattern, -1), status); michael@0: fStrictDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDashEquivalentsPattern, -1), status); michael@0: michael@0: michael@0: fDefaultGroupingSeparators = new UnicodeSet(*fDotEquivalents); michael@0: fDefaultGroupingSeparators->addAll(*fCommaEquivalents); michael@0: fDefaultGroupingSeparators->addAll(*fOtherGroupingSeparators); michael@0: michael@0: fStrictDefaultGroupingSeparators = new UnicodeSet(*fStrictDotEquivalents); michael@0: fStrictDefaultGroupingSeparators->addAll(*fStrictCommaEquivalents); michael@0: fStrictDefaultGroupingSeparators->addAll(*fStrictOtherGroupingSeparators); michael@0: michael@0: fMinusSigns = new UnicodeSet(); michael@0: fPlusSigns = new UnicodeSet(); michael@0: michael@0: // Check for null pointers michael@0: if (fDotEquivalents == NULL || fCommaEquivalents == NULL || fOtherGroupingSeparators == NULL || fDashEquivalents == NULL || michael@0: fStrictDotEquivalents == NULL || fStrictCommaEquivalents == NULL || fStrictOtherGroupingSeparators == NULL || fStrictDashEquivalents == NULL || michael@0: fDefaultGroupingSeparators == NULL || fStrictOtherGroupingSeparators == NULL || michael@0: fMinusSigns == NULL || fPlusSigns == NULL) { michael@0: cleanup(); michael@0: status = U_MEMORY_ALLOCATION_ERROR; michael@0: return; michael@0: } michael@0: michael@0: initUnicodeSet( michael@0: gMinusSigns, michael@0: sizeof(gMinusSigns) / sizeof(gMinusSigns[0]), michael@0: fMinusSigns); michael@0: initUnicodeSet( michael@0: gPlusSigns, michael@0: sizeof(gPlusSigns) / sizeof(gPlusSigns[0]), michael@0: fPlusSigns); michael@0: michael@0: // Freeze all the sets michael@0: fDotEquivalents->freeze(); michael@0: fCommaEquivalents->freeze(); michael@0: fOtherGroupingSeparators->freeze(); michael@0: fDashEquivalents->freeze(); michael@0: fStrictDotEquivalents->freeze(); michael@0: fStrictCommaEquivalents->freeze(); michael@0: fStrictOtherGroupingSeparators->freeze(); michael@0: fStrictDashEquivalents->freeze(); michael@0: fDefaultGroupingSeparators->freeze(); michael@0: fStrictDefaultGroupingSeparators->freeze(); michael@0: fMinusSigns->freeze(); michael@0: fPlusSigns->freeze(); michael@0: } michael@0: michael@0: DecimalFormatStaticSets::~DecimalFormatStaticSets() { michael@0: cleanup(); michael@0: } michael@0: michael@0: void DecimalFormatStaticSets::cleanup() { // Be sure to clean up newly added fields! michael@0: delete fDotEquivalents; fDotEquivalents = NULL; michael@0: delete fCommaEquivalents; fCommaEquivalents = NULL; michael@0: delete fOtherGroupingSeparators; fOtherGroupingSeparators = NULL; michael@0: delete fDashEquivalents; fDashEquivalents = NULL; michael@0: delete fStrictDotEquivalents; fStrictDotEquivalents = NULL; michael@0: delete fStrictCommaEquivalents; fStrictCommaEquivalents = NULL; michael@0: delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL; michael@0: delete fStrictDashEquivalents; fStrictDashEquivalents = NULL; michael@0: delete fDefaultGroupingSeparators; fDefaultGroupingSeparators = NULL; michael@0: delete fStrictDefaultGroupingSeparators; fStrictDefaultGroupingSeparators = NULL; michael@0: delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL; michael@0: delete fMinusSigns; fMinusSigns = NULL; michael@0: delete fPlusSigns; fPlusSigns = NULL; michael@0: } michael@0: michael@0: static DecimalFormatStaticSets *gStaticSets; michael@0: static icu::UInitOnce gStaticSetsInitOnce = U_INITONCE_INITIALIZER; michael@0: michael@0: michael@0: //------------------------------------------------------------------------------ michael@0: // michael@0: // decfmt_cleanup Memory cleanup function, free/delete all michael@0: // cached memory. Called by ICU's u_cleanup() function. michael@0: // michael@0: //------------------------------------------------------------------------------ michael@0: U_CDECL_BEGIN michael@0: static UBool U_CALLCONV michael@0: decimfmt_cleanup(void) michael@0: { michael@0: delete gStaticSets; michael@0: gStaticSets = NULL; michael@0: gStaticSetsInitOnce.reset(); michael@0: return TRUE; michael@0: } michael@0: michael@0: static void U_CALLCONV initSets(UErrorCode &status) { michael@0: U_ASSERT(gStaticSets == NULL); michael@0: ucln_i18n_registerCleanup(UCLN_I18N_DECFMT, decimfmt_cleanup); michael@0: gStaticSets = new DecimalFormatStaticSets(status); michael@0: if (U_FAILURE(status)) { michael@0: delete gStaticSets; michael@0: gStaticSets = NULL; michael@0: return; michael@0: } michael@0: if (gStaticSets == NULL) { michael@0: status = U_MEMORY_ALLOCATION_ERROR; michael@0: } michael@0: } michael@0: U_CDECL_END michael@0: michael@0: const DecimalFormatStaticSets *DecimalFormatStaticSets::getStaticSets(UErrorCode &status) { michael@0: umtx_initOnce(gStaticSetsInitOnce, initSets, status); michael@0: return gStaticSets; michael@0: } michael@0: michael@0: michael@0: const UnicodeSet *DecimalFormatStaticSets::getSimilarDecimals(UChar32 decimal, UBool strictParse) michael@0: { michael@0: UErrorCode status = U_ZERO_ERROR; michael@0: umtx_initOnce(gStaticSetsInitOnce, initSets, status); michael@0: if (U_FAILURE(status)) { michael@0: return NULL; michael@0: } michael@0: michael@0: if (gStaticSets->fDotEquivalents->contains(decimal)) { michael@0: return strictParse ? gStaticSets->fStrictDotEquivalents : gStaticSets->fDotEquivalents; michael@0: } michael@0: michael@0: if (gStaticSets->fCommaEquivalents->contains(decimal)) { michael@0: return strictParse ? gStaticSets->fStrictCommaEquivalents : gStaticSets->fCommaEquivalents; michael@0: } michael@0: michael@0: // if there is no match, return NULL michael@0: return NULL; michael@0: } michael@0: michael@0: michael@0: U_NAMESPACE_END michael@0: #endif // !UCONFIG_NO_FORMATTING