1/*
2 **********************************************************************
3 *   Copyright (C) 1997-2010, International Business Machines
4 *   Corporation and others.  All Rights Reserved.
5 **********************************************************************
6*
7* File locid.cpp
8*
9* Created by: Richard Gillam
10*
11* Modification History:
12*
13*   Date        Name        Description
14*   02/11/97    aliu        Changed gLocPath to fgDataDirectory and added
15*                           methods to get and set it.
16*   04/02/97    aliu        Made operator!= inline; fixed return value
17*                           of getName().
18*   04/15/97    aliu        Cleanup for AIX/Win32.
19*   04/24/97    aliu        Numerous changes per code review.
20*   08/18/98    stephen     Changed getDisplayName()
21*                           Added SIMPLIFIED_CHINESE, TRADITIONAL_CHINESE
22*                           Added getISOCountries(), getISOLanguages(),
23*                           getLanguagesForCountry()
24*   03/16/99    bertrand    rehaul.
25*   07/21/99    stephen     Added U_CFUNC setDefault
26*   11/09/99    weiv        Added const char * getName() const;
27*   04/12/00    srl         removing unicodestring api's and cached hash code
28*   08/10/01    grhoten     Change the static Locales to accessor functions
29******************************************************************************
30*/
31
32
33#include "unicode/locid.h"
34#include "unicode/uloc.h"
35#include "umutex.h"
36#include "uassert.h"
37#include "cmemory.h"
38#include "cstring.h"
39#include "uhash.h"
40#include "ucln_cmn.h"
41
42#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
43
44typedef enum ELocalePos {
45    eENGLISH,
46    eFRENCH,
47    eGERMAN,
48    eITALIAN,
49    eJAPANESE,
50    eKOREAN,
51    eCHINESE,
52
53    eFRANCE,
54    eGERMANY,
55    eITALY,
56    eJAPAN,
57    eKOREA,
58    eCHINA,      /* Alias for PRC */
59    eTAIWAN,
60    eUK,
61    eUS,
62    eCANADA,
63    eCANADA_FRENCH,
64    eROOT,
65
66
67    //eDEFAULT,
68    eMAX_LOCALES
69} ELocalePos;
70
71U_CFUNC int32_t locale_getKeywords(const char *localeID,
72            char prev,
73            char *keywords, int32_t keywordCapacity,
74            char *values, int32_t valuesCapacity, int32_t *valLen,
75            UBool valuesToo,
76            UErrorCode *status);
77
78static U_NAMESPACE_QUALIFIER Locale *gLocaleCache         = NULL;
79static U_NAMESPACE_QUALIFIER Locale *gDefaultLocale       = NULL;
80static UHashtable                   *gDefaultLocalesHashT = NULL;
81
82U_CDECL_BEGIN
83//
84// Deleter function for Locales owned by the default Locale hash table/
85//
86static void U_CALLCONV
87deleteLocale(void *obj) {
88    delete (U_NAMESPACE_QUALIFIER Locale *) obj;
89}
90
91static UBool U_CALLCONV locale_cleanup(void)
92{
93    U_NAMESPACE_USE
94
95    if (gLocaleCache) {
96        delete [] gLocaleCache;
97        gLocaleCache = NULL;
98    }
99
100    if (gDefaultLocalesHashT) {
101        uhash_close(gDefaultLocalesHashT);   // Automatically deletes all elements, using deleter func.
102        gDefaultLocalesHashT = NULL;
103    }
104    else if (gDefaultLocale) {
105        // The cache wasn't created, and only one default locale was created.
106        delete gDefaultLocale;
107    }
108    gDefaultLocale = NULL;
109
110    return TRUE;
111}
112U_CDECL_END
113
114U_NAMESPACE_BEGIN
115//
116//  locale_set_default_internal.
117//
118void locale_set_default_internal(const char *id)
119{
120    UErrorCode   status = U_ZERO_ERROR;
121    UBool canonicalize = FALSE;
122
123    // If given a NULL string for the locale id, grab the default
124    //   name from the system.
125    //   (Different from most other locale APIs, where a null name means use
126    //    the current ICU default locale.)
127    if (id == NULL) {
128        umtx_lock(NULL);
129        id = uprv_getDefaultLocaleID();
130        umtx_unlock(NULL);
131        canonicalize = TRUE; // always canonicalize host ID
132    }
133
134    // put the locale id into a canonical form,
135    //   in preparation for looking up this locale in the hash table of
136    //   already-created locale objects.
137    //
138    status = U_ZERO_ERROR;
139    char localeNameBuf[512];
140
141    if (canonicalize) {
142        uloc_canonicalize(id, localeNameBuf, sizeof(localeNameBuf)-1, &status);
143    } else {
144        uloc_getName(id, localeNameBuf, sizeof(localeNameBuf)-1, &status);
145    }
146    localeNameBuf[sizeof(localeNameBuf)-1] = 0;  // Force null termination in event of
147                                                 //   a long name filling the buffer.
148                                                 //   (long names are truncated.)
149
150    // Lazy creation of the hash table itself, if needed.
151    UBool isOnlyLocale;
152    UMTX_CHECK(NULL, (gDefaultLocale == NULL), isOnlyLocale);
153    if (isOnlyLocale) {
154        // We haven't seen this locale id before.
155        // Create a new Locale object for it.
156        Locale *newFirstDefault = new Locale(Locale::eBOGUS);
157        if (newFirstDefault == NULL) {
158            // No way to report errors from here.
159            return;
160        }
161        newFirstDefault->init(localeNameBuf, FALSE);
162        umtx_lock(NULL);
163        if (gDefaultLocale == NULL) {
164            gDefaultLocale = newFirstDefault;  // Assignment to gDefaultLocale must happen inside mutex
165            newFirstDefault = NULL;
166            ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
167        }
168        // Else some other thread raced us through here, and set the new Locale.
169        // Use the hash table next.
170        umtx_unlock(NULL);
171        if (newFirstDefault == NULL) {
172            // We were successful in setting the locale, and we were the first one to set it.
173            return;
174        }
175        // else start using the hash table.
176    }
177
178    // Lazy creation of the hash table itself, if needed.
179    UBool hashTableNeedsInit;
180    UMTX_CHECK(NULL, (gDefaultLocalesHashT == NULL), hashTableNeedsInit);
181    if (hashTableNeedsInit) {
182        status = U_ZERO_ERROR;
183        UHashtable *tHashTable = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
184        if (U_FAILURE(status)) {
185            return;
186        }
187        uhash_setValueDeleter(tHashTable, deleteLocale);
188        umtx_lock(NULL);
189        if (gDefaultLocalesHashT == NULL) {
190            gDefaultLocalesHashT = tHashTable;
191            ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
192        } else {
193            uhash_close(tHashTable);
194            hashTableNeedsInit = FALSE;
195        }
196        umtx_unlock(NULL);
197    }
198
199    // Hash table lookup, key is the locale full name
200    umtx_lock(NULL);
201    Locale *newDefault = (Locale *)uhash_get(gDefaultLocalesHashT, localeNameBuf);
202    if (newDefault != NULL) {
203        // We have the requested locale in the hash table already.
204        // Just set it as default.  Inside the mutex lock, for those troublesome processors.
205        gDefaultLocale = newDefault;
206        umtx_unlock(NULL);
207    } else {
208        umtx_unlock(NULL);
209        // We haven't seen this locale id before.
210        // Create a new Locale object for it.
211        newDefault = new Locale(Locale::eBOGUS);
212        if (newDefault == NULL) {
213            // No way to report errors from here.
214            return;
215        }
216        newDefault->init(localeNameBuf, FALSE);
217
218        // Add newly created Locale to the hash table of default Locales
219        const char *key = newDefault->getName();
220        U_ASSERT(uprv_strcmp(key, localeNameBuf) == 0);
221        umtx_lock(NULL);
222        Locale *hashTableVal = (Locale *)uhash_get(gDefaultLocalesHashT, key);
223        if (hashTableVal == NULL) {
224            if (hashTableNeedsInit) {
225                // This is the second request to set the locale.
226                // Cache the first one.
227                uhash_put(gDefaultLocalesHashT, (void *)gDefaultLocale->getName(), gDefaultLocale, &status);
228            }
229            uhash_put(gDefaultLocalesHashT, (void *)key, newDefault, &status);
230            gDefaultLocale = newDefault;
231            // ignore errors from hash table insert.  (Couldn't do anything anyway)
232            // We can still set the default Locale,
233            //  it just wont be cached, and will eventually leak.
234        } else {
235            // Some other thread raced us through here, and got the new Locale
236            //   into the hash table before us.  Use that one.
237            gDefaultLocale = hashTableVal;  // Assignment to gDefaultLocale must happen inside mutex
238            delete newDefault;
239        }
240        umtx_unlock(NULL);
241    }
242}
243U_NAMESPACE_END
244
245/* sfb 07/21/99 */
246U_CFUNC void
247locale_set_default(const char *id)
248{
249    U_NAMESPACE_USE
250    locale_set_default_internal(id);
251}
252/* end */
253
254U_CFUNC const char *
255locale_get_default(void)
256{
257    U_NAMESPACE_USE
258
259    return Locale::getDefault().getName();
260}
261
262
263U_NAMESPACE_BEGIN
264
265UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale)
266
267/*Character separating the posix id fields*/
268// '_'
269// In the platform codepage.
270#define SEP_CHAR '_'
271
272Locale::~Locale()
273{
274    /*if fullName is on the heap, we free it*/
275    if (fullName != fullNameBuffer)
276    {
277        uprv_free(fullName);
278        fullName = NULL;
279    }
280    if (baseName && baseName != baseNameBuffer) {
281        uprv_free(baseName);
282        baseName = NULL;
283    }
284}
285
286Locale::Locale()
287    : UObject(), fullName(fullNameBuffer), baseName(NULL)
288{
289    init(NULL, FALSE);
290}
291
292/*
293 * Internal constructor to allow construction of a locale object with
294 *   NO side effects.   (Default constructor tries to get
295 *   the default locale.)
296 */
297Locale::Locale(Locale::ELocaleType)
298    : UObject(), fullName(fullNameBuffer), baseName(NULL)
299{
300    setToBogus();
301}
302
303
304Locale::Locale( const   char * newLanguage,
305                const   char * newCountry,
306                const   char * newVariant,
307                const   char * newKeywords)
308    : UObject(), fullName(fullNameBuffer), baseName(NULL)
309{
310    if( (newLanguage==NULL) && (newCountry == NULL) && (newVariant == NULL) )
311    {
312        init(NULL, FALSE); /* shortcut */
313    }
314    else
315    {
316        MaybeStackArray<char, ULOC_FULLNAME_CAPACITY> togo;
317        int32_t size = 0;
318        int32_t lsize = 0;
319        int32_t csize = 0;
320        int32_t vsize = 0;
321        int32_t ksize = 0;
322        char    *p;
323
324        // Calculate the size of the resulting string.
325
326        // Language
327        if ( newLanguage != NULL )
328        {
329            lsize = (int32_t)uprv_strlen(newLanguage);
330            size = lsize;
331        }
332
333        // _Country
334        if ( newCountry != NULL )
335        {
336            csize = (int32_t)uprv_strlen(newCountry);
337            size += csize;
338        }
339
340        // _Variant
341        if ( newVariant != NULL )
342        {
343            // remove leading _'s
344            while(newVariant[0] == SEP_CHAR)
345            {
346                newVariant++;
347            }
348
349            // remove trailing _'s
350            vsize = (int32_t)uprv_strlen(newVariant);
351            while( (vsize>1) && (newVariant[vsize-1] == SEP_CHAR) )
352            {
353                vsize--;
354            }
355        }
356
357        if( vsize > 0 )
358        {
359            size += vsize;
360        }
361
362        // Separator rules:
363        if ( vsize > 0 )
364        {
365            size += 2;  // at least: __v
366        }
367        else if ( csize > 0 )
368        {
369            size += 1;  // at least: _v
370        }
371
372        if ( newKeywords != NULL)
373        {
374            ksize = (int32_t)uprv_strlen(newKeywords);
375            size += ksize + 1;
376        }
377
378
379        //  NOW we have the full locale string..
380
381        /*if the whole string is longer than our internal limit, we need
382        to go to the heap for temporary buffers*/
383        if (size >= togo.getCapacity())
384        {
385            // If togo_heap could not be created, initialize with default settings.
386            if (togo.resize(size+1) == NULL) {
387                init(NULL, FALSE);
388            }
389        }
390
391        togo[0] = 0;
392
393        // Now, copy it back.
394        p = togo.getAlias();
395        if ( lsize != 0 )
396        {
397            uprv_strcpy(p, newLanguage);
398            p += lsize;
399        }
400
401        if ( ( vsize != 0 ) || (csize != 0) )  // at least:  __v
402        {                                      //            ^
403            *p++ = SEP_CHAR;
404        }
405
406        if ( csize != 0 )
407        {
408            uprv_strcpy(p, newCountry);
409            p += csize;
410        }
411
412        if ( vsize != 0)
413        {
414            *p++ = SEP_CHAR; // at least: __v
415
416            uprv_strncpy(p, newVariant, vsize);  // Must use strncpy because
417            p += vsize;                          // of trimming (above).
418            *p = 0; // terminate
419        }
420
421        if ( ksize != 0)
422        {
423            if (uprv_strchr(newKeywords, '=')) {
424                *p++ = '@'; /* keyword parsing */
425            }
426            else {
427                *p++ = '_'; /* Variant parsing with a script */
428                if ( vsize == 0) {
429                    *p++ = '_'; /* No country found */
430                }
431            }
432            uprv_strcpy(p, newKeywords);
433            p += ksize;
434        }
435
436        // Parse it, because for example 'language' might really be a complete
437        // string.
438        init(togo.getAlias(), FALSE);
439    }
440}
441
442Locale::Locale(const Locale &other)
443    : UObject(other), fullName(fullNameBuffer), baseName(NULL)
444{
445    *this = other;
446}
447
448Locale &Locale::operator=(const Locale &other)
449{
450    if (this == &other) {
451        return *this;
452    }
453
454    if (&other == NULL) {
455        this->setToBogus();
456        return *this;
457    }
458
459    /* Free our current storage */
460    if(fullName != fullNameBuffer) {
461        uprv_free(fullName);
462        fullName = fullNameBuffer;
463    }
464
465    /* Allocate the full name if necessary */
466    if(other.fullName != other.fullNameBuffer) {
467        fullName = (char *)uprv_malloc(sizeof(char)*(uprv_strlen(other.fullName)+1));
468        if (fullName == NULL) {
469            return *this;
470        }
471    }
472    /* Copy the full name */
473    uprv_strcpy(fullName, other.fullName);
474
475    /* baseName is the cached result of getBaseName.  if 'other' has a
476       baseName and it fits in baseNameBuffer, then copy it. otherwise set
477       it to NULL, and let the user lazy-create it (in getBaseName) if they
478       want it. */
479    if(baseName && baseName != baseNameBuffer) {
480        uprv_free(baseName);
481    }
482    baseName = NULL;
483
484    if(other.baseName == other.baseNameBuffer) {
485        uprv_strcpy(baseNameBuffer, other.baseNameBuffer);
486        baseName = baseNameBuffer;
487    }
488
489    /* Copy the language and country fields */
490    uprv_strcpy(language, other.language);
491    uprv_strcpy(script, other.script);
492    uprv_strcpy(country, other.country);
493
494    /* The variantBegin is an offset, just copy it */
495    variantBegin = other.variantBegin;
496    fIsBogus = other.fIsBogus;
497    return *this;
498}
499
500Locale *
501Locale::clone() const {
502    return new Locale(*this);
503}
504
505UBool
506Locale::operator==( const   Locale& other) const
507{
508    return (uprv_strcmp(other.fullName, fullName) == 0);
509}
510
511/*This function initializes a Locale from a C locale ID*/
512Locale& Locale::init(const char* localeID, UBool canonicalize)
513{
514    fIsBogus = FALSE;
515    /* Free our current storage */
516    if(fullName != fullNameBuffer) {
517        uprv_free(fullName);
518        fullName = fullNameBuffer;
519    }
520
521    if(baseName && baseName != baseNameBuffer) {
522        uprv_free(baseName);
523        baseName = NULL;
524    }
525
526    // not a loop:
527    // just an easy way to have a common error-exit
528    // without goto and without another function
529    do {
530        char *separator;
531        char *field[5] = {0};
532        int32_t fieldLen[5] = {0};
533        int32_t fieldIdx;
534        int32_t variantField;
535        int32_t length;
536        UErrorCode err;
537
538        if(localeID == NULL) {
539            // not an error, just set the default locale
540            return *this = getDefault();
541        }
542
543        /* preset all fields to empty */
544        language[0] = script[0] = country[0] = 0;
545
546        // "canonicalize" the locale ID to ICU/Java format
547        err = U_ZERO_ERROR;
548        length = canonicalize ?
549            uloc_canonicalize(localeID, fullName, sizeof(fullNameBuffer), &err) :
550            uloc_getName(localeID, fullName, sizeof(fullNameBuffer), &err);
551
552        if(err == U_BUFFER_OVERFLOW_ERROR || length >= (int32_t)sizeof(fullNameBuffer)) {
553            /*Go to heap for the fullName if necessary*/
554            fullName = (char *)uprv_malloc(sizeof(char)*(length + 1));
555            if(fullName == 0) {
556                fullName = fullNameBuffer;
557                break; // error: out of memory
558            }
559            err = U_ZERO_ERROR;
560            length = canonicalize ?
561                uloc_canonicalize(localeID, fullName, length+1, &err) :
562                uloc_getName(localeID, fullName, length+1, &err);
563        }
564        if(U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) {
565            /* should never occur */
566            break;
567        }
568
569        variantBegin = length;
570
571        /* after uloc_getName/canonicalize() we know that only '_' are separators */
572        separator = field[0] = fullName;
573        fieldIdx = 1;
574        while ((separator = uprv_strchr(field[fieldIdx-1], SEP_CHAR)) && fieldIdx < (int32_t)(sizeof(field)/sizeof(field[0]))-1) {
575            field[fieldIdx] = separator + 1;
576            fieldLen[fieldIdx-1] = (int32_t)(separator - field[fieldIdx-1]);
577            fieldIdx++;
578        }
579        // variant may contain @foo or .foo POSIX cruft; remove it
580        separator = uprv_strchr(field[fieldIdx-1], '@');
581        char* sep2 = uprv_strchr(field[fieldIdx-1], '.');
582        if (separator!=NULL || sep2!=NULL) {
583            if (separator==NULL || (sep2!=NULL && separator > sep2)) {
584                separator = sep2;
585            }
586            fieldLen[fieldIdx-1] = (int32_t)(separator - field[fieldIdx-1]);
587        } else {
588            fieldLen[fieldIdx-1] = length - (int32_t)(field[fieldIdx-1] - fullName);
589        }
590
591        if (fieldLen[0] >= (int32_t)(sizeof(language))
592            || (fieldLen[1] == 4 && fieldLen[2] >= (int32_t)(sizeof(country)))
593            || (fieldLen[1] != 4 && fieldLen[1] >= (int32_t)(sizeof(country))))
594        {
595            break; // error: one of the fields is too long
596        }
597
598        variantField = 2; /* Usually the 2nd one, except when a script is used. */
599        if (fieldLen[0] > 0) {
600            /* We have a language */
601            uprv_memcpy(language, fullName, fieldLen[0]);
602            language[fieldLen[0]] = 0;
603        }
604        if (fieldLen[1] == 4) {
605            /* We have at least a script */
606            uprv_memcpy(script, field[1], fieldLen[1]);
607            script[fieldLen[1]] = 0;
608            variantField = 3;
609            if (fieldLen[2] > 0) {
610                /* We have a country */
611                uprv_memcpy(country, field[2], fieldLen[2]);
612                country[fieldLen[2]] = 0;
613            }
614        }
615        else if (fieldLen[1] > 0) {
616            /* We have a country and no script */
617            uprv_memcpy(country, field[1], fieldLen[1]);
618            country[fieldLen[1]] = 0;
619        }
620        if (variantField > 0 && fieldLen[variantField] > 0) {
621            /* We have a variant */
622            variantBegin = (int32_t)(field[variantField] - fullName);
623        }
624
625        // successful end of init()
626        return *this;
627    } while(0); /*loop doesn't iterate*/
628
629    // when an error occurs, then set this object to "bogus" (there is no UErrorCode here)
630    setToBogus();
631
632    return *this;
633}
634
635int32_t
636Locale::hashCode() const
637{
638    UHashTok hashKey;
639    hashKey.pointer = fullName;
640    return uhash_hashChars(hashKey);
641}
642
643void
644Locale::setToBogus() {
645    /* Free our current storage */
646    if(fullName != fullNameBuffer) {
647        uprv_free(fullName);
648        fullName = fullNameBuffer;
649    }
650    if(baseName && baseName != baseNameBuffer) {
651        uprv_free(baseName);
652        baseName = NULL;
653    }
654    *fullNameBuffer = 0;
655    *language = 0;
656    *script = 0;
657    *country = 0;
658    fIsBogus = TRUE;
659}
660
661const Locale& U_EXPORT2
662Locale::getDefault()
663{
664    const Locale *retLocale;
665    UMTX_CHECK(NULL, gDefaultLocale, retLocale);
666    if (retLocale == NULL) {
667        locale_set_default_internal(NULL);
668        umtx_lock(NULL);
669        // Need a mutex  in case some other thread set a new
670        // default inbetween when we set and when we get the new default.  For
671        // processors with weak memory coherency, we might not otherwise see all
672        // of the newly created new default locale.
673        retLocale = gDefaultLocale;
674        umtx_unlock(NULL);
675    }
676    return *retLocale;
677}
678
679
680
681void U_EXPORT2
682Locale::setDefault( const   Locale&     newLocale,
683                            UErrorCode&  status)
684{
685    if (U_FAILURE(status)) {
686        return;
687    }
688
689    /* Set the default from the full name string of the supplied locale.
690     * This is a convenient way to access the default locale caching mechanisms.
691     */
692    const char *localeID = newLocale.getName();
693    locale_set_default_internal(localeID);
694}
695
696Locale U_EXPORT2
697Locale::createFromName (const char *name)
698{
699    if (name) {
700        Locale l("");
701        l.init(name, FALSE);
702        return l;
703    }
704    else {
705        return getDefault();
706    }
707}
708
709Locale U_EXPORT2
710Locale::createCanonical(const char* name) {
711    Locale loc("");
712    loc.init(name, TRUE);
713    return loc;
714}
715
716const char *
717Locale::getISO3Language() const
718{
719    return uloc_getISO3Language(fullName);
720}
721
722
723const char *
724Locale::getISO3Country() const
725{
726    return uloc_getISO3Country(fullName);
727}
728
729/**
730 * Return the LCID value as specified in the "LocaleID" resource for this
731 * locale.  The LocaleID must be expressed as a hexadecimal number, from
732 * one to four digits.  If the LocaleID resource is not present, or is
733 * in an incorrect format, 0 is returned.  The LocaleID is for use in
734 * Windows (it is an LCID), but is available on all platforms.
735 */
736uint32_t
737Locale::getLCID() const
738{
739    return uloc_getLCID(fullName);
740}
741
742const char* const* U_EXPORT2 Locale::getISOCountries()
743{
744    return uloc_getISOCountries();
745}
746
747const char* const* U_EXPORT2 Locale::getISOLanguages()
748{
749    return uloc_getISOLanguages();
750}
751
752// Set the locale's data based on a posix id.
753void Locale::setFromPOSIXID(const char *posixID)
754{
755    init(posixID, TRUE);
756}
757
758const Locale & U_EXPORT2
759Locale::getRoot(void)
760{
761    return getLocale(eROOT);
762}
763
764const Locale & U_EXPORT2
765Locale::getEnglish(void)
766{
767    return getLocale(eENGLISH);
768}
769
770const Locale & U_EXPORT2
771Locale::getFrench(void)
772{
773    return getLocale(eFRENCH);
774}
775
776const Locale & U_EXPORT2
777Locale::getGerman(void)
778{
779    return getLocale(eGERMAN);
780}
781
782const Locale & U_EXPORT2
783Locale::getItalian(void)
784{
785    return getLocale(eITALIAN);
786}
787
788const Locale & U_EXPORT2
789Locale::getJapanese(void)
790{
791    return getLocale(eJAPANESE);
792}
793
794const Locale & U_EXPORT2
795Locale::getKorean(void)
796{
797    return getLocale(eKOREAN);
798}
799
800const Locale & U_EXPORT2
801Locale::getChinese(void)
802{
803    return getLocale(eCHINESE);
804}
805
806const Locale & U_EXPORT2
807Locale::getSimplifiedChinese(void)
808{
809    return getLocale(eCHINA);
810}
811
812const Locale & U_EXPORT2
813Locale::getTraditionalChinese(void)
814{
815    return getLocale(eTAIWAN);
816}
817
818
819const Locale & U_EXPORT2
820Locale::getFrance(void)
821{
822    return getLocale(eFRANCE);
823}
824
825const Locale & U_EXPORT2
826Locale::getGermany(void)
827{
828    return getLocale(eGERMANY);
829}
830
831const Locale & U_EXPORT2
832Locale::getItaly(void)
833{
834    return getLocale(eITALY);
835}
836
837const Locale & U_EXPORT2
838Locale::getJapan(void)
839{
840    return getLocale(eJAPAN);
841}
842
843const Locale & U_EXPORT2
844Locale::getKorea(void)
845{
846    return getLocale(eKOREA);
847}
848
849const Locale & U_EXPORT2
850Locale::getChina(void)
851{
852    return getLocale(eCHINA);
853}
854
855const Locale & U_EXPORT2
856Locale::getPRC(void)
857{
858    return getLocale(eCHINA);
859}
860
861const Locale & U_EXPORT2
862Locale::getTaiwan(void)
863{
864    return getLocale(eTAIWAN);
865}
866
867const Locale & U_EXPORT2
868Locale::getUK(void)
869{
870    return getLocale(eUK);
871}
872
873const Locale & U_EXPORT2
874Locale::getUS(void)
875{
876    return getLocale(eUS);
877}
878
879const Locale & U_EXPORT2
880Locale::getCanada(void)
881{
882    return getLocale(eCANADA);
883}
884
885const Locale & U_EXPORT2
886Locale::getCanadaFrench(void)
887{
888    return getLocale(eCANADA_FRENCH);
889}
890
891const Locale &
892Locale::getLocale(int locid)
893{
894    Locale *localeCache = getLocaleCache();
895    U_ASSERT((locid < eMAX_LOCALES)&&(locid>=0));
896    if (localeCache == NULL) {
897        // Failure allocating the locale cache.
898        //   The best we can do is return a NULL reference.
899        locid = 0;
900    }
901    return localeCache[locid]; /*operating on NULL*/
902}
903
904/*
905This function is defined this way in order to get around static
906initialization and static destruction.
907 */
908Locale *
909Locale::getLocaleCache(void)
910{
911    umtx_lock(NULL);
912    UBool needInit = (gLocaleCache == NULL);
913    umtx_unlock(NULL);
914
915    if (needInit) {
916        Locale *tLocaleCache = new Locale[(int)eMAX_LOCALES];
917        if (tLocaleCache == NULL) {
918            return NULL;
919        }
920	tLocaleCache[eROOT]          = Locale("");
921        tLocaleCache[eENGLISH]       = Locale("en");
922        tLocaleCache[eFRENCH]        = Locale("fr");
923        tLocaleCache[eGERMAN]        = Locale("de");
924        tLocaleCache[eITALIAN]       = Locale("it");
925        tLocaleCache[eJAPANESE]      = Locale("ja");
926        tLocaleCache[eKOREAN]        = Locale("ko");
927        tLocaleCache[eCHINESE]       = Locale("zh");
928        tLocaleCache[eFRANCE]        = Locale("fr", "FR");
929        tLocaleCache[eGERMANY]       = Locale("de", "DE");
930        tLocaleCache[eITALY]         = Locale("it", "IT");
931        tLocaleCache[eJAPAN]         = Locale("ja", "JP");
932        tLocaleCache[eKOREA]         = Locale("ko", "KR");
933        tLocaleCache[eCHINA]         = Locale("zh", "CN");
934        tLocaleCache[eTAIWAN]        = Locale("zh", "TW");
935        tLocaleCache[eUK]            = Locale("en", "GB");
936        tLocaleCache[eUS]            = Locale("en", "US");
937        tLocaleCache[eCANADA]        = Locale("en", "CA");
938        tLocaleCache[eCANADA_FRENCH] = Locale("fr", "CA");
939
940        umtx_lock(NULL);
941        if (gLocaleCache == NULL) {
942            gLocaleCache = tLocaleCache;
943            tLocaleCache = NULL;
944            ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
945        }
946        umtx_unlock(NULL);
947        if (tLocaleCache) {
948            delete [] tLocaleCache;  // Fancy array delete will destruct each member.
949        }
950    }
951    return gLocaleCache;
952}
953
954class KeywordEnumeration : public StringEnumeration {
955private:
956    char *keywords;
957    char *current;
958    int32_t length;
959    UnicodeString currUSKey;
960    static const char fgClassID;/* Warning this is used beyond the typical RTTI usage. */
961
962public:
963    static UClassID U_EXPORT2 getStaticClassID(void) { return (UClassID)&fgClassID; }
964    virtual UClassID getDynamicClassID(void) const { return getStaticClassID(); }
965public:
966    KeywordEnumeration(const char *keys, int32_t keywordLen, int32_t currentIndex, UErrorCode &status)
967        : keywords((char *)&fgClassID), current((char *)&fgClassID), length(0) {
968        if(U_SUCCESS(status) && keywordLen != 0) {
969            if(keys == NULL || keywordLen < 0) {
970                status = U_ILLEGAL_ARGUMENT_ERROR;
971            } else {
972                keywords = (char *)uprv_malloc(keywordLen+1);
973                if (keywords == NULL) {
974                    status = U_MEMORY_ALLOCATION_ERROR;
975                }
976                else {
977                    uprv_memcpy(keywords, keys, keywordLen);
978                    keywords[keywordLen] = 0;
979                    current = keywords + currentIndex;
980                    length = keywordLen;
981                }
982            }
983        }
984    }
985
986    virtual ~KeywordEnumeration() {
987        uprv_free(keywords);
988    }
989
990    virtual StringEnumeration * clone() const
991    {
992        UErrorCode status = U_ZERO_ERROR;
993        return new KeywordEnumeration(keywords, length, (int32_t)(current - keywords), status);
994    }
995
996    virtual int32_t count(UErrorCode &/*status*/) const {
997        char *kw = keywords;
998        int32_t result = 0;
999        while(*kw) {
1000            result++;
1001            kw += uprv_strlen(kw)+1;
1002        }
1003        return result;
1004    }
1005
1006    virtual const char* next(int32_t* resultLength, UErrorCode& status) {
1007        const char* result;
1008        int32_t len;
1009        if(U_SUCCESS(status) && *current != 0) {
1010            result = current;
1011            len = (int32_t)uprv_strlen(current);
1012            current += len+1;
1013            if(resultLength != NULL) {
1014                *resultLength = len;
1015            }
1016        } else {
1017            if(resultLength != NULL) {
1018                *resultLength = 0;
1019            }
1020            result = NULL;
1021        }
1022        return result;
1023    }
1024
1025    virtual const UnicodeString* snext(UErrorCode& status) {
1026        int32_t resultLength = 0;
1027        const char *s = next(&resultLength, status);
1028        return setChars(s, resultLength, status);
1029    }
1030
1031    virtual void reset(UErrorCode& /*status*/) {
1032        current = keywords;
1033    }
1034};
1035
1036const char KeywordEnumeration::fgClassID = '\0';
1037
1038StringEnumeration *
1039Locale::createKeywords(UErrorCode &status) const
1040{
1041    char keywords[256];
1042    int32_t keywordCapacity = 256;
1043    StringEnumeration *result = NULL;
1044
1045    const char* variantStart = uprv_strchr(fullName, '@');
1046    const char* assignment = uprv_strchr(fullName, '=');
1047    if(variantStart) {
1048        if(assignment > variantStart) {
1049            int32_t keyLen = locale_getKeywords(variantStart+1, '@', keywords, keywordCapacity, NULL, 0, NULL, FALSE, &status);
1050            if(keyLen) {
1051                result = new KeywordEnumeration(keywords, keyLen, 0, status);
1052            }
1053        } else {
1054            status = U_INVALID_FORMAT_ERROR;
1055        }
1056    }
1057    return result;
1058}
1059
1060int32_t
1061Locale::getKeywordValue(const char* keywordName, char *buffer, int32_t bufLen, UErrorCode &status) const
1062{
1063    return uloc_getKeywordValue(fullName, keywordName, buffer, bufLen, &status);
1064}
1065
1066void
1067Locale::setKeywordValue(const char* keywordName, const char* keywordValue, UErrorCode &status)
1068{
1069    uloc_setKeywordValue(keywordName, keywordValue, fullName, ULOC_FULLNAME_CAPACITY, &status);
1070}
1071
1072const char *
1073Locale::getBaseName() const
1074{
1075    // lazy init
1076    UErrorCode status = U_ZERO_ERROR;
1077    // semantically const
1078    if(baseName == 0) {
1079        ((Locale *)this)->baseName = ((Locale *)this)->baseNameBuffer;
1080        int32_t baseNameSize = uloc_getBaseName(fullName, baseName, ULOC_FULLNAME_CAPACITY, &status);
1081        if(baseNameSize >= ULOC_FULLNAME_CAPACITY) {
1082            ((Locale *)this)->baseName = (char *)uprv_malloc(sizeof(char) * baseNameSize + 1);
1083            if (baseName == NULL) {
1084                return baseName;
1085            }
1086            uloc_getBaseName(fullName, baseName, baseNameSize+1, &status);
1087        }
1088        baseName[baseNameSize] = 0;
1089
1090        // the computation of variantBegin leaves it equal to the length
1091        // of fullName if there is no variant.  It should instead be
1092        // the length of the baseName.  Patch around this for now.
1093        if (variantBegin == (int32_t)uprv_strlen(fullName)) {
1094          ((Locale*)this)->variantBegin = baseNameSize;
1095        }
1096    }
1097    return baseName;
1098}
1099
1100//eof
1101U_NAMESPACE_END
1102