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 
initUnicodeSet(const UChar32 * raw,int32_t len,UnicodeSet * s)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 
DecimalFormatStaticSets(UErrorCode & status)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 
~DecimalFormatStaticSets()166 DecimalFormatStaticSets::~DecimalFormatStaticSets() {
167   cleanup();
168 }
169 
cleanup()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
decimfmt_cleanup(void)198 decimfmt_cleanup(void)
199 {
200     delete gStaticSets;
201     gStaticSets = NULL;
202     gStaticSetsInitOnce.reset();
203     return TRUE;
204 }
205 
initSets(UErrorCode & status)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 
getStaticSets(UErrorCode & status)221 const DecimalFormatStaticSets *DecimalFormatStaticSets::getStaticSets(UErrorCode &status) {
222     umtx_initOnce(gStaticSetsInitOnce, initSets, status);
223     return gStaticSets;
224 }
225 
226 
getSimilarDecimals(UChar32 decimal,UBool strictParse)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