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 29 U_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 40 static const UChar gDotEquivalentsPattern[] = { 41 // [ . \u2024 \u3002 \uFE12 \uFE52 \uFF0E \uFF61 ] 42 0x005B, 0x002E, 0x2024, 0x3002, 0xFE12, 0xFE52, 0xFF0E, 0xFF61, 0x005D, 0x0000}; 43 44 static 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 48 static 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 52 static const UChar gDashEquivalentsPattern[] = { 53 // [ \ - HYPHEN F_DASH N_DASH MINUS ] 54 0x005B, 0x005C, 0x002D, 0x2010, 0x2012, 0x2013, 0x2212, 0x005D, 0x0000}; 55 56 static const UChar gStrictDotEquivalentsPattern[] = { 57 // [ . \u2024 \uFE52 \uFF0E \uFF61 ] 58 0x005B, 0x002E, 0x2024, 0xFE52, 0xFF0E, 0xFF61, 0x005D, 0x0000}; 59 60 static const UChar gStrictCommaEquivalentsPattern[] = { 61 // [ , \u066B \uFE10 \uFE50 \uFF0C ] 62 0x005B, 0x002C, 0x066B, 0xFE10, 0xFE50, 0xFF0C, 0x005D, 0x0000}; 63 64 static 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 68 static const UChar gStrictDashEquivalentsPattern[] = { 69 // [ \ - MINUS ] 70 0x005B, 0x005C, 0x002D, 0x2212, 0x005D, 0x0000}; 71 72 static UChar32 gMinusSigns[] = { 73 0x002D, 74 0x207B, 75 0x208B, 76 0x2212, 77 0x2796, 78 0xFE63, 79 0xFF0D}; 80 81 static UChar32 gPlusSigns[] = { 82 0x002B, 83 0x207A, 84 0x208A, 85 0x2795, 86 0xfB29, 87 0xFE62, 88 0xFF0B}; 89 90 static 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 96 DecimalFormatStaticSets::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 166 DecimalFormatStaticSets::~DecimalFormatStaticSets() { 167 cleanup(); 168 } 169 170 void 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 186 static DecimalFormatStaticSets *gStaticSets; 187 static 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 //------------------------------------------------------------------------------ 196 U_CDECL_BEGIN 197 static UBool U_CALLCONV 198 decimfmt_cleanup(void) 199 { 200 delete gStaticSets; 201 gStaticSets = NULL; 202 gStaticSetsInitOnce.reset(); 203 return TRUE; 204 } 205 206 static 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 } 219 U_CDECL_END 220 221 const DecimalFormatStaticSets *DecimalFormatStaticSets::getStaticSets(UErrorCode &status) { 222 umtx_initOnce(gStaticSetsInitOnce, initSets, status); 223 return gStaticSets; 224 } 225 226 227 const 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 248 U_NAMESPACE_END 249 #endif // !UCONFIG_NO_FORMATTING 250