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