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