1/* 2******************************************************************************* 3* Copyright (C) 2009-2013, International Business Machines Corporation and * 4* others. All Rights Reserved. * 5******************************************************************************* 6* 7* This file contains the class DecimalFormatStaticSets 8* 9* DecimalFormatStaticSets holds the UnicodeSets that are needed for lenient 10* parsing of decimal and group separators. 11******************************************************************************** 12*/ 13 14#include "unicode/utypes.h" 15 16#if !UCONFIG_NO_FORMATTING 17 18#include "unicode/unistr.h" 19#include "unicode/uniset.h" 20#include "unicode/uchar.h" 21#include "cmemory.h" 22#include "cstring.h" 23#include "uassert.h" 24#include "ucln_in.h" 25#include "umutex.h" 26 27#include "decfmtst.h" 28 29U_NAMESPACE_BEGIN 30 31 32//------------------------------------------------------------------------------ 33// 34// Unicode Set pattern strings for all of the required constant sets. 35// Initialized with hex values for portability to EBCDIC based machines. 36// Really ugly, but there's no good way to avoid it. 37// 38//------------------------------------------------------------------------------ 39 40static const UChar gDotEquivalentsPattern[] = { 41 // [ . \u2024 \u3002 \uFE12 \uFE52 \uFF0E \uFF61 ] 42 0x005B, 0x002E, 0x2024, 0x3002, 0xFE12, 0xFE52, 0xFF0E, 0xFF61, 0x005D, 0x0000}; 43 44static const UChar gCommaEquivalentsPattern[] = { 45 // [ , \u060C \u066B \u3001 \uFE10 \uFE11 \uFE50 \uFE51 \uFF0C \uFF64 ] 46 0x005B, 0x002C, 0x060C, 0x066B, 0x3001, 0xFE10, 0xFE11, 0xFE50, 0xFE51, 0xFF0C, 0xFF64, 0x005D, 0x0000}; 47 48static const UChar gOtherGroupingSeparatorsPattern[] = { 49 // [ \ SPACE ' NBSP \u066C \u2000 - \u200A \u2018 \u2019 \u202F \u205F \u3000 \uFF07 ] 50 0x005B, 0x005C, 0x0020, 0x0027, 0x00A0, 0x066C, 0x2000, 0x002D, 0x200A, 0x2018, 0x2019, 0x202F, 0x205F, 0x3000, 0xFF07, 0x005D, 0x0000}; 51 52static const UChar gDashEquivalentsPattern[] = { 53 // [ \ - HYPHEN F_DASH N_DASH MINUS ] 54 0x005B, 0x005C, 0x002D, 0x2010, 0x2012, 0x2013, 0x2212, 0x005D, 0x0000}; 55 56static const UChar gStrictDotEquivalentsPattern[] = { 57 // [ . \u2024 \uFE52 \uFF0E \uFF61 ] 58 0x005B, 0x002E, 0x2024, 0xFE52, 0xFF0E, 0xFF61, 0x005D, 0x0000}; 59 60static const UChar gStrictCommaEquivalentsPattern[] = { 61 // [ , \u066B \uFE10 \uFE50 \uFF0C ] 62 0x005B, 0x002C, 0x066B, 0xFE10, 0xFE50, 0xFF0C, 0x005D, 0x0000}; 63 64static const UChar gStrictOtherGroupingSeparatorsPattern[] = { 65 // [ \ SPACE ' NBSP \u066C \u2000 - \u200A \u2018 \u2019 \u202F \u205F \u3000 \uFF07 ] 66 0x005B, 0x005C, 0x0020, 0x0027, 0x00A0, 0x066C, 0x2000, 0x002D, 0x200A, 0x2018, 0x2019, 0x202F, 0x205F, 0x3000, 0xFF07, 0x005D, 0x0000}; 67 68static const UChar gStrictDashEquivalentsPattern[] = { 69 // [ \ - MINUS ] 70 0x005B, 0x005C, 0x002D, 0x2212, 0x005D, 0x0000}; 71 72static UChar32 gMinusSigns[] = { 73 0x002D, 74 0x207B, 75 0x208B, 76 0x2212, 77 0x2796, 78 0xFE63, 79 0xFF0D}; 80 81static UChar32 gPlusSigns[] = { 82 0x002B, 83 0x207A, 84 0x208A, 85 0x2795, 86 0xfB29, 87 0xFE62, 88 0xFF0B}; 89 90static void initUnicodeSet(const UChar32 *raw, int32_t len, UnicodeSet *s) { 91 for (int32_t i = 0; i < len; ++i) { 92 s->add(raw[i]); 93 } 94} 95 96DecimalFormatStaticSets::DecimalFormatStaticSets(UErrorCode &status) 97: fDotEquivalents(NULL), 98 fCommaEquivalents(NULL), 99 fOtherGroupingSeparators(NULL), 100 fDashEquivalents(NULL), 101 fStrictDotEquivalents(NULL), 102 fStrictCommaEquivalents(NULL), 103 fStrictOtherGroupingSeparators(NULL), 104 fStrictDashEquivalents(NULL), 105 fDefaultGroupingSeparators(NULL), 106 fStrictDefaultGroupingSeparators(NULL), 107 fMinusSigns(NULL), 108 fPlusSigns(NULL) 109{ 110 fDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gDotEquivalentsPattern, -1), status); 111 fCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gCommaEquivalentsPattern, -1), status); 112 fOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gOtherGroupingSeparatorsPattern, -1), status); 113 fDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gDashEquivalentsPattern, -1), status); 114 115 fStrictDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDotEquivalentsPattern, -1), status); 116 fStrictCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictCommaEquivalentsPattern, -1), status); 117 fStrictOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gStrictOtherGroupingSeparatorsPattern, -1), status); 118 fStrictDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDashEquivalentsPattern, -1), status); 119 120 121 fDefaultGroupingSeparators = new UnicodeSet(*fDotEquivalents); 122 fDefaultGroupingSeparators->addAll(*fCommaEquivalents); 123 fDefaultGroupingSeparators->addAll(*fOtherGroupingSeparators); 124 125 fStrictDefaultGroupingSeparators = new UnicodeSet(*fStrictDotEquivalents); 126 fStrictDefaultGroupingSeparators->addAll(*fStrictCommaEquivalents); 127 fStrictDefaultGroupingSeparators->addAll(*fStrictOtherGroupingSeparators); 128 129 fMinusSigns = new UnicodeSet(); 130 fPlusSigns = new UnicodeSet(); 131 132 // Check for null pointers 133 if (fDotEquivalents == NULL || fCommaEquivalents == NULL || fOtherGroupingSeparators == NULL || fDashEquivalents == NULL || 134 fStrictDotEquivalents == NULL || fStrictCommaEquivalents == NULL || fStrictOtherGroupingSeparators == NULL || fStrictDashEquivalents == NULL || 135 fDefaultGroupingSeparators == NULL || fStrictOtherGroupingSeparators == NULL || 136 fMinusSigns == NULL || fPlusSigns == NULL) { 137 cleanup(); 138 status = U_MEMORY_ALLOCATION_ERROR; 139 return; 140 } 141 142 initUnicodeSet( 143 gMinusSigns, 144 sizeof(gMinusSigns) / sizeof(gMinusSigns[0]), 145 fMinusSigns); 146 initUnicodeSet( 147 gPlusSigns, 148 sizeof(gPlusSigns) / sizeof(gPlusSigns[0]), 149 fPlusSigns); 150 151 // Freeze all the sets 152 fDotEquivalents->freeze(); 153 fCommaEquivalents->freeze(); 154 fOtherGroupingSeparators->freeze(); 155 fDashEquivalents->freeze(); 156 fStrictDotEquivalents->freeze(); 157 fStrictCommaEquivalents->freeze(); 158 fStrictOtherGroupingSeparators->freeze(); 159 fStrictDashEquivalents->freeze(); 160 fDefaultGroupingSeparators->freeze(); 161 fStrictDefaultGroupingSeparators->freeze(); 162 fMinusSigns->freeze(); 163 fPlusSigns->freeze(); 164} 165 166DecimalFormatStaticSets::~DecimalFormatStaticSets() { 167 cleanup(); 168} 169 170void DecimalFormatStaticSets::cleanup() { // Be sure to clean up newly added fields! 171 delete fDotEquivalents; fDotEquivalents = NULL; 172 delete fCommaEquivalents; fCommaEquivalents = NULL; 173 delete fOtherGroupingSeparators; fOtherGroupingSeparators = NULL; 174 delete fDashEquivalents; fDashEquivalents = NULL; 175 delete fStrictDotEquivalents; fStrictDotEquivalents = NULL; 176 delete fStrictCommaEquivalents; fStrictCommaEquivalents = NULL; 177 delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL; 178 delete fStrictDashEquivalents; fStrictDashEquivalents = NULL; 179 delete fDefaultGroupingSeparators; fDefaultGroupingSeparators = NULL; 180 delete fStrictDefaultGroupingSeparators; fStrictDefaultGroupingSeparators = NULL; 181 delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL; 182 delete fMinusSigns; fMinusSigns = NULL; 183 delete fPlusSigns; fPlusSigns = NULL; 184} 185 186static DecimalFormatStaticSets *gStaticSets; 187static icu::UInitOnce gStaticSetsInitOnce = U_INITONCE_INITIALIZER; 188 189 190//------------------------------------------------------------------------------ 191// 192// decfmt_cleanup Memory cleanup function, free/delete all 193// cached memory. Called by ICU's u_cleanup() function. 194// 195//------------------------------------------------------------------------------ 196U_CDECL_BEGIN 197static UBool U_CALLCONV 198decimfmt_cleanup(void) 199{ 200 delete gStaticSets; 201 gStaticSets = NULL; 202 gStaticSetsInitOnce.reset(); 203 return TRUE; 204} 205 206static void U_CALLCONV initSets(UErrorCode &status) { 207 U_ASSERT(gStaticSets == NULL); 208 ucln_i18n_registerCleanup(UCLN_I18N_DECFMT, decimfmt_cleanup); 209 gStaticSets = new DecimalFormatStaticSets(status); 210 if (U_FAILURE(status)) { 211 delete gStaticSets; 212 gStaticSets = NULL; 213 return; 214 } 215 if (gStaticSets == NULL) { 216 status = U_MEMORY_ALLOCATION_ERROR; 217 } 218} 219U_CDECL_END 220 221const DecimalFormatStaticSets *DecimalFormatStaticSets::getStaticSets(UErrorCode &status) { 222 umtx_initOnce(gStaticSetsInitOnce, initSets, status); 223 return gStaticSets; 224} 225 226 227const UnicodeSet *DecimalFormatStaticSets::getSimilarDecimals(UChar32 decimal, UBool strictParse) 228{ 229 UErrorCode status = U_ZERO_ERROR; 230 umtx_initOnce(gStaticSetsInitOnce, initSets, status); 231 if (U_FAILURE(status)) { 232 return NULL; 233 } 234 235 if (gStaticSets->fDotEquivalents->contains(decimal)) { 236 return strictParse ? gStaticSets->fStrictDotEquivalents : gStaticSets->fDotEquivalents; 237 } 238 239 if (gStaticSets->fCommaEquivalents->contains(decimal)) { 240 return strictParse ? gStaticSets->fStrictCommaEquivalents : gStaticSets->fCommaEquivalents; 241 } 242 243 // if there is no match, return NULL 244 return NULL; 245} 246 247 248U_NAMESPACE_END 249#endif // !UCONFIG_NO_FORMATTING 250