home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Programming / ICU / src / icu / source / common / locid.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-19  |  22.2 KB  |  847 lines

  1. /*
  2. *******************************************************************************
  3. *                                                                             *
  4. * COPYRIGHT:                                                                  *
  5. *   (C) Copyright Taligent, Inc.,  1996                                       *
  6. *   (C) Copyright International Business Machines Corporation,  1996-1998     *
  7. *   Licensed Material - Program-Property of IBM - All Rights Reserved.        *
  8. *   US Government Users Restricted Rights - Use, duplication, or disclosure   *
  9. *   restricted by GSA ADP Schedule Contract with IBM Corp.                    *
  10. *                                                                             *
  11. *******************************************************************************
  12. *
  13. * File locid.cpp
  14. *
  15. * Created by: Richard Gillam
  16. *
  17. * Modification History:
  18. *
  19. *   Date        Name        Description
  20. *   02/11/97    aliu        Changed gLocPath to fgDataDirectory and added 
  21. *                           methods to get and set it.
  22. *   04/02/97    aliu        Made operator!= inline; fixed return value 
  23. *                           of getName().
  24. *   04/15/97    aliu        Cleanup for AIX/Win32.
  25. *   04/24/97    aliu        Numerous changes per code review.
  26. *   08/18/98    stephen     Changed getDisplayName()
  27. *                           Added SIMPLIFIED_CHINESE, TRADITIONAL_CHINESE
  28. *                           Added getISOCountries(), getISOLanguages(),
  29. *                           getLanguagesForCountry()
  30. *   03/16/99    bertrand    rehaul.
  31. *   07/21/99    stephen     Added U_CFUNC setDefault
  32. *******************************************************************************
  33. */
  34.  
  35.  
  36.  
  37. #include "uhash.h"
  38. #include "locid.h"
  39. #include "uloc.h"
  40. #include "resbund.h"
  41. #include "mutex.h"
  42. #include "unicode.h"
  43. #include "cmemory.h"
  44. #include "cstring.h"
  45.  
  46. /**
  47.  * static variables
  48.  */
  49. Locale Locale::fgDefaultLocale;
  50.  
  51. Locale*            Locale::localeList = NULL;
  52. int32_t            Locale::localeListCount;
  53. UnicodeString*    Locale::isoLanguages = NULL;
  54. int32_t            Locale::isoLanguagesCount;
  55. UnicodeString*    Locale::isoCountries = NULL;;
  56. int32_t            Locale::isoCountriesCount;
  57.  
  58.  
  59.  
  60.  
  61. /**
  62.  * Constant definitions
  63.  */
  64. const Locale  Locale::ENGLISH("en");
  65. const Locale  Locale::FRENCH("fr");
  66. const Locale  Locale::GERMAN("de");
  67. const Locale  Locale::ITALIAN("it");
  68. const Locale  Locale::JAPANESE("ja");
  69. const Locale  Locale::KOREAN("ko");
  70. const Locale  Locale::CHINESE("zh");
  71. const Locale  Locale::SIMPLIFIED_CHINESE("zh", "CN");   
  72. const Locale  Locale::TRADITIONAL_CHINESE("zh", "TW");
  73.  
  74. // Useful constant for country.
  75.  
  76. const Locale  Locale::FRANCE("fr", "FR");
  77. const Locale  Locale::GERMANY("de", "DE");
  78. const Locale  Locale::ITALY("it", "IT");
  79. const Locale  Locale::JAPAN("ja", "JP");
  80. const Locale  Locale::KOREA("en", "GB");
  81. const Locale  Locale::CHINA("zh", "CN");
  82. const Locale  Locale::PRC("zh", "CN");
  83. const Locale  Locale::TAIWAN("zh", "TW");
  84. const Locale  Locale::UK("en", "GB");
  85. const Locale  Locale::US("en", "US");
  86. const Locale  Locale::CANADA("en", "CA");
  87. const Locale  Locale::CANADA_FRENCH("fr", "CA");
  88.  
  89.  
  90.     /**
  91.      * Table mapping ISO country codes to the ISO language codes of the languages spoken
  92.      * in those countries.
  93.      * (Because the Java VM specification for building arrays and hashtables causes
  94.      * code that builds the tables element by element to be produces, we compress the data
  95.      * into a single encoded String, and lazy evaluate the table from it.)
  96.      */
  97.     UHashtable* Locale::ctry2LangMapping = 0;
  98.     const UnicodeString Locale::compressedCtry2LangMapping =
  99.         "ADfresAEarenAFpsAGenAIrnALsqAMhyruANnlenAOptAResASensmATdeAUenAWnlenAZazhyru\
  100. BAsrshhrslmksqBBenBDbnhibhenBEfrnldeBFfrBGbgtrBHarenBIrnfrswBJfrBMenBNmsenzh\
  101. BOesayquBRptBSenBTdzenneBVnoBWentnBYberuBZenesCAenfrCCenCFfrsgCGfrCHfrdeitrm\
  102. CIfrCKmienCLesCMenfrCNzhboCOesCResCUesCVptCXenCYeltrenCZcsskDEdeDJarfrsoDKda\
  103. DMenfrDOesDZarfrECesquEEetruEGarenfrEHarfritERamtiarenitESeseucaglETamaren\
  104. FIfisvFJenfjhiFKenFMenFOfodaFRfreubrcoFXfrGAfrGBengdcyGDenfrGEkahyruGFfrGHen\
  105. GIenesGLdaikklGMenwoGNfrGPfrenGQesGRelGTesGUenGWptGYenhiurHKzhenHNesHRhrHTfr\
  106. HUhuIDinennlIEengaILiwarjiINhienguknksmlmrneorpasatateIOenIQarkutkIRfaarku\
  107. ISisITitfrdeJMenJOarJPjaKEenswKGkyKHkmKIenKMfrarKNenKPkoKRkoKWarenKYenKZkkru\
  108. LAlofrLBarenfrLCenfrLIdeLKtasienLRenLSstenLTltruplLUfrdeLVlvltruLYarenit\
  109. MAarfresMCfrenitMDmorobgMGmgenfrMKmkshtrMLfrMMmyMNmnruMOzhptMQfrMRarfrMSen\
  110. MTmtenitMUenfrhiMWenMXesMYmsenMZptNAenafdeNEfrhaNFenNGenhayoNIesNLnlfyNOno\
  111. NPneNRnaenNUenNZenmiOMarenPAesenPEesquayPFfrPGenPHentlesPKurenpspasdPLplPMfren\
  112. PNenPResenPTptPWenPYesgnQAarenREfrtaROrohuRUruRWenfrrwSAarSBenSCenfrSDarsu\
  113. SEsvSGzhenmstaSHenSIslSJnoSKskhuplshSLenSMitSNfrSOarenitsoSRnleneshiSTptSVes\
  114. SYarSZenssTCenTDfrarTFfrTGfrTHthTJtgruuzTKenmiTMtkruTNarTOentoTRtrkuTTenTVen\
  115. TWzhTZenswUAukruUGenswUMenUSenesUYesUZuzruVAlaitVCenVEesVGenVIenVNvizhfr\
  116. VUenfrbiWFfrWSensmYEarYTfrmgswYUsrshmkhuZAafenZMenZRfrswZWensn";
  117.  
  118. /*Used for stack allocation of temporary buffers
  119.  *can be tweaked  for speed and likelihood of resorting to heap allocation*/ 
  120. #define BUFFER_SIZE 50
  121.  
  122. /*Character separating the posix id fields*/
  123. const UChar sep = 0x005F; // '_'
  124.  
  125.  
  126. Locale::~Locale()
  127. {   
  128.   /*if fullName is on the heap, we delete it*/
  129.   if (fullName != fullNameBuffer) 
  130.     {
  131.       delete []fullName;
  132.     }
  133. }
  134.  
  135. Locale::Locale()
  136. {
  137.     init(uloc_getDefault());
  138. }
  139.  
  140. Locale::Locale( const   UnicodeString&  newLanguage)
  141. {
  142.   UnicodeString togo(newLanguage);
  143.   char myLocaleID[ULOC_FULLNAME_CAPACITY];
  144.   int32_t size = newLanguage.size();
  145.  
  146.   togo.extract(0,size, myLocaleID);
  147.   myLocaleID[size] = '\0';
  148.   init(myLocaleID);
  149. }
  150.  
  151. Locale::Locale( const   UnicodeString&  newLanguage, 
  152.                 const   UnicodeString&  newCountry)
  153. {
  154.   UnicodeString togo(newLanguage);
  155.   char myLocaleID[ULOC_FULLNAME_CAPACITY];
  156.   
  157.  
  158.   togo += sep;
  159.   togo += newCountry;
  160.  
  161.   
  162.   int size = togo.size();
  163.  
  164.   togo.extract(0,size, myLocaleID);
  165.   myLocaleID[size] = '\0';
  166.   init(myLocaleID);
  167. }
  168.  
  169.  
  170. Locale::Locale( const   UnicodeString&  newLanguage, 
  171.                 const   UnicodeString&  newCountry, 
  172.                 const   UnicodeString&  newVariant) 
  173. {
  174.   UnicodeString togo(newLanguage);
  175.   
  176.   char myLocaleID[ULOC_FULLNAME_CAPACITY];
  177.   UnicodeString newVariantCopy(newVariant);
  178.   
  179.   
  180.   if (newCountry.size() > 0 ||
  181.       newVariantCopy.size() > 0 )
  182.     {
  183.       togo += sep;
  184.       togo += newCountry;
  185.     }
  186.   
  187.   int vsize = newVariantCopy.size();
  188.     if (vsize > 0)
  189.       {
  190.     int i = 0;
  191.     //We need to trim variant codes : (_*)$var(_*) --> $var 
  192.     while ((i<vsize) && newVariantCopy[i] == sep) newVariantCopy.remove(i++, 1);
  193.     i = newVariantCopy.size() - 1;
  194.     while (i && (newVariantCopy[i] == sep)) newVariantCopy.remove(i--, 1);
  195.     
  196.     togo += sep ;
  197.     togo += newVariantCopy ;
  198.       }
  199.   
  200.   int size = togo.size();
  201.  
  202.   /*is the variant is longer than our internal limit, we need
  203.   to go to the heap for temporary buffers*/
  204.   if (size > ULOC_FULLNAME_CAPACITY)
  205.     {
  206.       char *togo_heap = new char[size+1];
  207.       togo.extract(0,size, togo_heap);
  208.       togo_heap[size] = '\0';
  209.       init(togo_heap);
  210.       delete []togo_heap;
  211.     }
  212.   else 
  213.     {
  214.       togo.extract(0,size, myLocaleID);
  215.       myLocaleID[size] = '\0';
  216.       init(myLocaleID);
  217.     }
  218.   
  219. }
  220.  
  221. Locale::Locale(const    Locale& other)
  222.  
  223. {
  224.   int j;
  225.     /*Copy the language and country fields*/
  226.   icu_strcpy(language, other.language);
  227.   icu_strcpy(country, other.country);
  228.   
  229.   /*make fullName point to the heap if necessary*/
  230.   if ((j=icu_strlen(other.fullName)) > ULOC_FULLNAME_CAPACITY)
  231.     {
  232.       fullName = new char[j+1];
  233.     }
  234.   else fullName = fullNameBuffer;
  235.   
  236.   icu_strcpy(fullName, other.fullName);
  237.     
  238.     /*Make the variant point to the same offset as the copied*/
  239.   variant = fullName + (other.variant - other.fullName) ;
  240.   khashCode = other.khashCode;
  241. }
  242.  
  243. bool_t
  244. Locale::operator==( const   Locale& other) const
  245. {
  246.   if (icu_strcmp(other.language, language) == 0)    
  247.   {
  248.     if (icu_strcmp(other.country, country) == 0)    
  249.     {
  250.       if (icu_strcmp(other.variant, variant) == 0)    return TRUE;
  251.     }
  252.   }
  253.   
  254.   return FALSE;
  255.   
  256. }
  257.  
  258. /*This function initializes a Locale from a C locale ID*/
  259. Locale& Locale::init(const char* localeID)
  260. {
  261.   int k,l;
  262.   UErrorCode err = U_ZERO_ERROR;
  263.  
  264.   if (localeID == NULL) localeID = uloc_getDefault();
  265.   l = uloc_getLanguage(localeID, 
  266.                this->language,
  267.                ULOC_LANG_CAPACITY,
  268.                &err);
  269.  
  270.   l += k = uloc_getCountry(localeID,
  271.               this->country,
  272.               ULOC_COUNTRY_CAPACITY,
  273.               &err);
  274.   
  275.   l--; //adjust for the 2 zero terminators
  276.   
  277.   /*Go to heap for the fullName if necessary*/
  278.   int j;
  279.   if ((j=icu_strlen(localeID)) > ULOC_FULLNAME_CAPACITY)
  280.     {
  281.       this->fullName = new char[j+1];
  282.     }
  283.   else this->fullName = this->fullNameBuffer;
  284.   
  285.   icu_strcpy(this->fullName, localeID);
  286.       
  287.   /*Setting up the variant:
  288.     -point to the zero terminator of fullName if there is none
  289.     -point to the first character of the variant if ther is one
  290.     */
  291.   if (k > 1)  
  292.     {
  293.       if (this->fullName[l] == '\0') this->variant = this->fullName + l;
  294.       else this->variant = this->fullName + l + 1 ;
  295.     }
  296.   else this->variant = this->fullName + l - 1;
  297.  
  298.   setHashCode();
  299.   
  300.   return *this;
  301. }
  302.  
  303.  
  304.  
  305. Locale& Locale::operator=(const Locale& other)
  306. {
  307.   icu_strcpy(language, other.language);
  308.   icu_strcpy(country, other.country);
  309.   if (other.fullName == other.fullNameBuffer)    fullName = fullNameBuffer;
  310.   else 
  311.   {
  312.     /*In case the assigner has some of its data on the heap
  313.      * we need to do the same*/
  314.     if (fullName != fullNameBuffer) delete []fullName;
  315.     fullName = new char[(icu_strlen(other.fullName)+1)];
  316.   }
  317.   icu_strcpy(fullName, other.fullName);
  318.   /*Make the variant point to the same offset as the assigner*/
  319.   variant = fullName + (other.variant - other.fullName) ;
  320.  
  321.   khashCode = other.khashCode;
  322.  
  323.   return *this;
  324. }
  325.  
  326. int32_t
  327. Locale::hashCode() const 
  328. {
  329.   return khashCode;
  330. }
  331.  
  332. void
  333. Locale::setHashCode()
  334. {
  335.   UnicodeString fullNameUString = language;
  336.   fullNameUString += country;
  337.   fullNameUString += variant;
  338.   const UChar *key       = fullNameUString.getUChars();
  339.   int32_t len           = fullNameUString.size();
  340.   int32_t hash          = 0;
  341.   const UChar *limit     = key + len;
  342.   int32_t inc           = (len >= 128 ? len/64 : 1);
  343.   
  344.   /*
  345.     We compute the hash by iterating sparsely over 64 (at most) characters
  346.     spaced evenly through the string.  For each character, we multiply the
  347.     previous hash value by a prime number and add the new character in,
  348.     in the manner of a additive linear congruential random number generator,
  349.     thus producing a pseudorandom deterministic value which should be well
  350.     distributed over the output range. [LIU]
  351.   */
  352.  
  353.   while(key < limit) 
  354.     {
  355.       hash = (hash * 37) + (char)*key;
  356.       key += inc;
  357.     }
  358.   
  359.   if(hash == 0)    hash = 1;
  360.   
  361.   khashCode = hash & 0x7FFFFFFF;
  362. }
  363.  
  364.  
  365. Locale&
  366. Locale::getDefault() 
  367. {
  368.   return fgDefaultLocale;
  369. }
  370.  
  371. /* sfb 07/21/99 */
  372. U_CFUNC void
  373. locale_set_default(const char *id)
  374. {
  375.   Locale::getDefault().init(id);
  376. }
  377. /* end */
  378.  
  379. void 
  380. Locale::setDefault( const   Locale&     newLocale, 
  381.                             UErrorCode&  status) 
  382. {
  383.     if (U_FAILURE(status)) return;
  384.  
  385.     uloc_setDefault(newLocale.fullName, &status);
  386.     
  387.     fgDefaultLocale = newLocale;
  388. }
  389.  
  390. UnicodeString& 
  391. Locale::getLanguage(UnicodeString& lang) const
  392. {
  393.   lang = language;
  394.   return lang;
  395. }
  396.  
  397. UnicodeString& 
  398. Locale::getCountry(UnicodeString& cntry) const
  399. {
  400.   cntry = country;
  401.   return cntry;
  402. }
  403.  
  404. UnicodeString& 
  405. Locale::getVariant(UnicodeString& var) const
  406. {
  407.   var = variant;
  408.   return var;
  409. }
  410.  
  411. UnicodeString& 
  412. Locale::getName(UnicodeString& name) const
  413. {
  414.   name = fullName;
  415.   return name;
  416. }
  417.  
  418. // deprecated
  419. UnicodeString& 
  420. Locale::getISO3Language(UnicodeString& lang) const
  421. {
  422.     lang = uloc_getISO3Language(fullName);
  423.     return lang;
  424. }
  425.  
  426. UnicodeString& 
  427. Locale::getISO3Language(UnicodeString& lang, UErrorCode& status) const
  428. {
  429.     if(U_FAILURE(status))
  430.       return lang;
  431.  
  432.     lang = uloc_getISO3Language(fullName);
  433.     if (lang.size() == 0)
  434.       status = U_MISSING_RESOURCE_ERROR;
  435.     
  436.     return lang;
  437. }
  438.  
  439. // deprecated
  440. UnicodeString& 
  441. Locale::getISO3Country(UnicodeString& cntry) const
  442. {
  443.     cntry = uloc_getISO3Country(fullName);
  444.     return cntry;
  445. }
  446.  
  447. UnicodeString& 
  448. Locale::getISO3Country(UnicodeString& cntry, UErrorCode& status) const
  449. {
  450.     if(U_FAILURE(status))
  451.         return cntry;
  452.  
  453.     cntry = uloc_getISO3Country(fullName);
  454.     if (cntry.size() == 0)
  455.         status = U_MISSING_RESOURCE_ERROR;
  456.  
  457.     return cntry;
  458. }
  459.  
  460. /**
  461.  * Return the LCID value as specified in the "LocaleID" resource for this
  462.  * locale.  The LocaleID must be expressed as a hexadecimal number, from
  463.  * one to four digits.  If the LocaleID resource is not present, or is
  464.  * in an incorrect format, 0 is returned.  The LocaleID is for use in
  465.  * Windows (it is an LCID), but is available on all platforms.
  466.  */
  467. uint32_t 
  468. Locale::getLCID() const
  469. {
  470.     return uloc_getLCID(fullName);
  471. }
  472.  
  473. UnicodeString& 
  474. Locale::getDisplayLanguage(UnicodeString& dispLang) const
  475. {
  476.     return this->getDisplayLanguage(getDefault(), dispLang);
  477. }
  478.  
  479. /*We cannot make any assumptions on the size of the output display strings
  480. * Yet, since we are calling through to a C API, we need to set limits on
  481. * buffer size. For all the following getDisplay functions we first attempt
  482. * to fill up a stack allocated buffer. If it is to small we heap allocated
  483. * the exact buffer we need copy it to the UnicodeString and delete it*/
  484.  
  485. UnicodeString&
  486. Locale::getDisplayLanguage( const   Locale&         inLocale,
  487.                 UnicodeString&  dispLang) const
  488. {
  489.   UErrorCode status = U_ZERO_ERROR;
  490.   UChar bufBuffer[BUFFER_SIZE];
  491.   UChar* buf = bufBuffer;
  492.   
  493.   //  dispLang = "result";
  494.   //  return dispLang;
  495.   int size = uloc_getDisplayLanguage(fullName,
  496.                      inLocale.fullName,
  497.                      buf,
  498.                      BUFFER_SIZE,
  499.                      &status);
  500.   
  501.  
  502.   if (status == U_BUFFER_OVERFLOW_ERROR)
  503.     {
  504.       status = U_ZERO_ERROR;
  505.       buf = new UChar[size];
  506.       
  507.       uloc_getDisplayLanguage(fullName,
  508.                   inLocale.fullName,
  509.                   buf,
  510.                   size,
  511.                   &status);
  512.       
  513.     }
  514.   
  515.   dispLang = buf;
  516.  
  517.   if (buf != bufBuffer) delete []buf;
  518.   
  519.   return dispLang;
  520. }
  521.  
  522. UnicodeString& 
  523. Locale::getDisplayCountry(UnicodeString& dispCntry) const
  524. {
  525.     return this->getDisplayCountry(getDefault(), dispCntry);
  526. }
  527.  
  528. UnicodeString& 
  529. Locale::getDisplayCountry(  const   Locale&         inLocale,
  530.                                     UnicodeString&  dispCntry) const
  531. {
  532.   UErrorCode status = U_ZERO_ERROR;
  533.   UChar bufBuffer[BUFFER_SIZE];
  534.   UChar* buf = bufBuffer;
  535.   
  536.   
  537.   int size = uloc_getDisplayCountry(fullName,
  538.                     inLocale.fullName,
  539.                     buf,
  540.                     BUFFER_SIZE,
  541.                     &status);
  542.   
  543.   if (status == U_BUFFER_OVERFLOW_ERROR)
  544.     {
  545.       status = U_ZERO_ERROR;
  546.       buf = new UChar[size];
  547.       uloc_getDisplayCountry(fullName,
  548.                  inLocale.fullName,
  549.                  buf,
  550.                  size,
  551.                  &status);
  552.       
  553.       
  554.     }
  555.  
  556.   
  557.   dispCntry = buf;
  558.  
  559.   if (buf != bufBuffer) delete []buf;
  560.   
  561.   return dispCntry;
  562. }
  563.  
  564. UnicodeString& 
  565. Locale::getDisplayVariant(UnicodeString& dispVar) const
  566. {
  567.   return this->getDisplayVariant(getDefault(), dispVar);
  568.   
  569. }
  570.  
  571. UnicodeString& Locale::getDisplayVariant(const Locale& inLocale,
  572.                      UnicodeString& dispVar) const
  573. {
  574.   UErrorCode status = U_ZERO_ERROR;
  575.   UChar bufBuffer[BUFFER_SIZE];
  576.   UChar* buf = bufBuffer;
  577.   
  578.  
  579.   int size = uloc_getDisplayVariant(fullName,
  580.                     inLocale.fullName,
  581.                     buf,
  582.                     BUFFER_SIZE,
  583.                     &status);
  584.   
  585.   if (status == U_BUFFER_OVERFLOW_ERROR)
  586.     {
  587.       status = U_ZERO_ERROR;
  588.       buf = new UChar[size];
  589.       uloc_getDisplayVariant(fullName,
  590.                  inLocale.fullName,
  591.                  buf,
  592.                  size,
  593.                  &status);
  594.       
  595.     }
  596.   
  597.  
  598.   dispVar = buf;
  599.   
  600.   if (buf != bufBuffer) delete []buf;
  601.   
  602.   return dispVar;
  603. }
  604.  
  605. UnicodeString& 
  606. Locale::getDisplayName( UnicodeString& name ) const
  607. {
  608.     return this->getDisplayName(getDefault(), name);
  609. }
  610.  
  611. UnicodeString& 
  612. Locale::getDisplayName( const   Locale&     inLocale,
  613.             UnicodeString& result) const
  614. {
  615.   UErrorCode status = U_ZERO_ERROR;
  616.   UChar bufBuffer[BUFFER_SIZE];
  617.   UChar* buf = bufBuffer;
  618.   
  619.   int size = uloc_getDisplayName(fullName,
  620.                  inLocale.fullName,
  621.                  buf,
  622.                  BUFFER_SIZE,
  623.                  &status);
  624.   
  625.   if (status == U_BUFFER_OVERFLOW_ERROR)
  626.     {
  627.       status = U_ZERO_ERROR;
  628.       
  629.       buf = new UChar[size];
  630.       uloc_getDisplayName(fullName,
  631.               inLocale.fullName,
  632.               buf,
  633.               size,
  634.               &status);    
  635.     }
  636.  
  637.     result = buf;
  638.   
  639.   if (buf != bufBuffer) {delete []buf;}
  640.   
  641.   return result;
  642. }
  643.  
  644. const Locale*
  645. Locale::getAvailableLocales(int32_t& count) 
  646. {
  647.   // for now, there is a hardcoded list, so just walk through that list and set it up.
  648.   if (localeList == 0)
  649.     {
  650.       const UnicodeString* ids = ResourceBundle::listInstalledLocales(getDataDirectory(), count);
  651.       Locale *newLocaleList = new Locale[count];
  652.       
  653.       for(int32_t i = 0; i < count; i++) 
  654.     newLocaleList[i].setFromPOSIXID(ids[i]);
  655.       
  656.       Mutex mutex;
  657.       if(localeList != 0) {
  658.     delete []newLocaleList;
  659.       }
  660.       else {
  661.     localeListCount = count;
  662.             localeList = newLocaleList;
  663.       }
  664.     }
  665.   count = localeListCount;
  666.   return localeList;
  667. }
  668.  
  669.  
  670. /**
  671.  * Returns a list of all 2-letter country codes defined in ISO 3166.
  672.  * Can be used to create Locales.
  673.  */
  674. const UnicodeString*
  675. Locale::getISOCountries(int32_t& count) 
  676. {
  677.   if(isoCountries == 0) {
  678.     const char* const*    cResult = uloc_getISOCountries();
  679.     int32_t tempCount;
  680.     
  681.     int i;
  682.     tempCount = 0;
  683.     for (i = 0; cResult[i] != NULL; i++)      ++tempCount;
  684.     
  685.     UnicodeString *temp = new UnicodeString [tempCount];
  686.     
  687.     for(i = 0; i < tempCount; ++i)
  688.       temp[i] = cResult[i];
  689.     
  690.     Mutex mutex;        
  691.     if(isoCountries != 0)
  692.       delete [] temp;
  693.     else {
  694.       isoCountries = temp;
  695.       isoCountriesCount = tempCount;
  696.     }
  697.   }
  698.   
  699.   count = isoCountriesCount;
  700.  
  701.  
  702.   return isoCountries;
  703. }
  704.  
  705. /**
  706.  * Returns a list of all 2-letter language codes defined in ISO 639.
  707.  * Can be used to create Locales.
  708.  * [NOTE:  ISO 639 is not a stable standard-- some languages' codes have changed.
  709.  * The list this function returns includes both the new and the old codes for the
  710.  * languages whose codes have changed.]
  711.  */
  712. const UnicodeString* 
  713. Locale::getISOLanguages(int32_t& count) 
  714. {
  715.   if(isoLanguages == 0) {
  716.     const char* const* cResult = uloc_getISOLanguages();
  717.     int32_t tempCount;
  718.     
  719.     int i;
  720.     tempCount = 0;
  721.     for (i = 0; cResult[i] != NULL; i++)   ++tempCount;
  722.     
  723.     UnicodeString *temp = new UnicodeString [tempCount];
  724.     
  725.     for(i = 0; i < tempCount; ++i)
  726.       temp[i] = cResult[i];
  727.     
  728.     Mutex mutex;        
  729.     if(isoLanguages != 0)
  730.       delete [] temp;
  731.     else {
  732.       isoLanguages = temp;
  733.       isoLanguagesCount = tempCount;
  734.     }
  735.   }
  736.   
  737.   count = isoLanguagesCount;
  738.   return isoLanguages;
  739. }
  740.  
  741. /**
  742.  * Given an ISO country code, returns an array of Strings containing the ISO
  743.  * codes of the languages spoken in that country.  Official languages are listed
  744.  * in the returned table before unofficial languages, but other than that, the
  745.  * order of the returned list is indeterminate.  If the value the user passes in
  746.  * for "country" is not a valid ISO 316 country code, or if we don't have language
  747.  * information for the specified country, this function returns an empty array.
  748.  *
  749.  * [This function is not currently part of Locale's API, but is needed in the
  750.  * implementation.  We hope to add it to the API in a future release.]
  751.  */
  752. const UnicodeString* 
  753. Locale::getLanguagesForCountry(const UnicodeString& country, int32_t& count) 
  754. {
  755.   // To save on the size of a static array in the .class file, we keep the
  756.   // data around encoded into a String.  The first time this function is called,
  757.   // the String s parsed to produce a Hashtable, which is then used for all
  758.   // lookups.
  759.   if(ctry2LangMapping == 0) {
  760.     UErrorCode err = U_ZERO_ERROR;
  761.     UHashtable *temp = uhash_open(uhash_hashUString, &err);
  762.     if (U_FAILURE(err)) 
  763.       {
  764.     count = 0;
  765.     return NULL;
  766.       }
  767.     
  768.     int32_t i = 0;
  769.     int32_t j;
  770.     int32_t count = sizeof(compressedCtry2LangMapping) / sizeof(compressedCtry2LangMapping[0]);
  771.     while (i < count) {
  772.       UnicodeString key;
  773.       compressedCtry2LangMapping.extractBetween(i, i + 2, key);
  774.       i += 2;
  775.       for(j = i; j < count; j += 2)
  776.     if(Unicode::isUpperCase(compressedCtry2LangMapping[j]))
  777.       break;
  778.       UnicodeString compressedValues;
  779.       compressedCtry2LangMapping.extractBetween(i, j, compressedValues);
  780.       UnicodeString *values = new UnicodeString[compressedValues.size() / 2];
  781.       int32_t valLen = sizeof(values) / sizeof(values[0]);
  782.       for (int32_t k = 0; k < valLen; ++k)
  783.     compressedValues.extractBetween(k * 2, (k * 2) + 2, values[k]);
  784.       uhash_putKey(temp, uhash_hashUString((void*)key.getUChars()),values,&err);
  785.       i = j;
  786.     }
  787.     
  788.     Mutex mutex;
  789.     if(ctry2LangMapping != 0)
  790.       uhash_close(temp);
  791.     else
  792.       ctry2LangMapping = temp;
  793.   }
  794.   
  795.   const UnicodeString *result = (const UnicodeString*)uhash_get(ctry2LangMapping,uhash_hashUString(country.getUChars()));
  796.   if(result == 0)
  797.     count = 0;
  798.   else
  799.     count = sizeof(result) / sizeof(result[0]);
  800.   
  801.   return result;
  802. }
  803.  
  804.  
  805. /**
  806.  * Get the path to the locale files.  This path will be a platform-specific
  807.  * path name ending in a directory separator, so that file names may be
  808.  * concatenated to it.
  809.  */
  810. const   char*       Locale::getDataDirectory()
  811. {
  812.   return uloc_getDataDirectory();
  813. }
  814.  
  815. /**
  816.  * Set the path to the locale files.
  817.  */
  818. void                Locale::setDataDirectory(const char* path)
  819. {
  820.   uloc_setDataDirectory(path);
  821. }
  822.  
  823. // ================= privates =====================================
  824.  
  825.  
  826.  
  827.  
  828. // Set the locale's data based on a posix id. 
  829. void Locale::setFromPOSIXID(const char *posixID)
  830. {
  831.   init(posixID);  
  832. }
  833.  
  834. // Set the locale's data based on a posix id.
  835. void Locale::setFromPOSIXID(const UnicodeString &posixIDString)
  836. {
  837.     char onStack[20];
  838.     char* buffer = onStack;
  839.     if (posixIDString.size() >= 20)      buffer = new char[posixIDString.size()+1];
  840.     posixIDString.extract(0, posixIDString.size(), buffer);
  841.     buffer[posixIDString.size()] = '\0';
  842.     init(buffer);
  843.     if (buffer != onStack)    delete [] buffer;
  844. }
  845.  
  846. //eof
  847.