Home | History | Annotate | Download | only in i18n
      1 //  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 const UChar32 gMinusSigns[] = {
     75     0x002D,
     76     0x207B,
     77     0x208B,
     78     0x2212,
     79     0x2796,
     80     0xFE63,
     81     0xFF0D};
     82 
     83 static const 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