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