home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Programming / ICU / src / icu / source / common / uloc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-19  |  32.6 KB  |  1,194 lines

  1. /*
  2. *******************************************************************************
  3. *                                                                             *
  4. * COPYRIGHT:                                                                  *
  5. *   (C) Copyright Taligent, Inc.,  1997                                       *
  6. *   (C) Copyright International Business Machines Corporation,  1997-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 ULOC.CPP
  14. *
  15. * Modification History:
  16. *
  17. *   Date        Name        Description
  18. *   04/01/97    aliu        Creation.
  19. *   08/21/98    stephen     JDK 1.2 sync
  20. *   12/08/98    rtg         New Locale implementation and C API
  21. *   03/15/99    damiba      overhaul.
  22. *   04/06/99    stephen     changed setDefault() to realloc and copy
  23. *   06/14/99    stephen     Changed calls to ures_open for new params
  24. *   07/21/99    stephen     Modified setDefault() to propagate to C++
  25. ******************************************************************************/
  26.  
  27.  
  28. #include "uloc.h"
  29.  
  30. #include "utypes.h"
  31. #include "ures.h"
  32. #include "uchar.h"
  33. #include "umutex.h"
  34. #include "cstring.h"
  35. #include "ustring.h"
  36. #include "cmemory.h"
  37.  
  38. /****************************************************************************
  39.   Global variable and type definitions
  40. ******************************************************************************/
  41.  
  42. /* UnicodeString stuff */
  43. typedef struct UnicodeString UnicodeString;
  44.  
  45. U_CAPI const UChar* T_UnicodeString_getUChars(const UnicodeString *s);
  46. /* Locale stuff */
  47. U_CAPI void locale_set_default(const char *id);
  48.  
  49. /* These strings describe the resources we attempt to load from
  50.  the locale ResourceBundle data file.*/
  51. static const char* _kLocaleString   = "LocaleString";
  52. static const char* _kShortLanguage  = "ShortLanguage";
  53. static const char* _kShortCountry   = "ShortCountry";
  54. static const char* _kLocaleID       = "LocaleID";
  55. static const char* _kLanguages      = "Languages";
  56. static const char* _kCountries      = "Countries";
  57.  
  58.  
  59. #define TEMPBUFSIZE 8
  60.  
  61. /*Some static strings needed in the getDisplay* functions*/
  62. static const UChar openParen[] = { (UChar)0x0020 /* space */, (UChar)0x0028 /* ( */, (UChar)0x0000};
  63. static const UChar comma[] = { (UChar)0x002C /* space */, (UChar)0x0020 /* , */, (UChar)0x0000};
  64. static const UChar closeParen[] = { (UChar)0x0029 /* ( */, (UChar)0x0000};
  65.  
  66.  
  67. static char* _defaultLocale = NULL;
  68. static char* _dataDirectory = NULL;
  69.  
  70. static char** _installedLocales = NULL;
  71. static int32_t _installedLocalesCount = 0;
  72.  
  73.  
  74. static const char _languages[] =
  75. "aa\0ab\0af\0am\0ar\0as\0ay\0az\0"
  76. "ba\0be\0bg\0bh\0bi\0bn\0bo\0br\0"
  77. "ca\0co\0cs\0cy\0da\0de\0dz\0"
  78. "el\0en\0eo\0es\0et\0eu\0fa\0fi\0fj\0fo\0fr\0fy\0"
  79. "ga\0gd\0gl\0gn\0gu\0ha\0he\0hi\0hr\0hu\0hy\0"
  80. "ia\0id\0ie\0ik\0in\0is\0it\0iu\0iw\0"
  81. "ja\0ji\0jw\0ka\0kk\0kl\0km\0kn\0ko\0ks\0ku\0ky\0"
  82. "la\0ln\0lo\0lt\0lv\0"
  83. "mg\0mi\0mk\0ml\0mn\0mo\0mr\0ms\0mt\0my\0"
  84. "na\0ne\0nl\0no\0oc\0om\0or\0"
  85. "pa\0pl\0ps\0pt\0qu\0rm\0rn\0ro\0ru\0rw\0"
  86. "sa\0sd\0sg\0sh\0si\0sk\0sl\0sm\0sn\0so\0sq\0sr\0ss\0st\0su\0sv\0sw\0"
  87. "ta\0te\0tg\0th\0ti\0tk\0tl\0tn\0to\0tr\0ts\0tt\0tw\0"
  88. "ug\0uk\0ur\0uz\0vi\0vo\0wo\0xh\0yi\0yo\0za\0zh\0zu";
  89. /* This list MUST be in sorted order, and MUST contain only two-letter codes! */
  90.  
  91. static const char _languages3[] =
  92. "aar\0abk\0afr\0amh\0ara\0asm\0aym\0aze\0"
  93. "bak\0bel\0bul\0bih\0bis\0ben\0bod\0bre\0"
  94. "cat\0cos\0ces\0cym\0dan\0deu\0dzo\0"
  95. "ell\0eng\0epo\0spa\0est\0eus\0fas\0fin\0fij\0fao\0fra\0fry\0"
  96. "gai\0gdh\0glg\0grn\0guj\0hau\0heb\0hin\0hrv\0hun\0hye\0"
  97. "ina\0ind\0ile\0ipk\0ind\0isl\0ita\0iku\0heb\0"
  98. "jpn\0yid\0jaw\0kat\0kaz\0kal\0khm\0kan\0kor\0kas\0kur\0kir\0"
  99. "lat\0lin\0lao\0lit\0lav\0"
  100.     "mlg\0mri\0mkd\0mal\0mon\0mol\0mar\0msa\0mlt\0mya\0"
  101. "nau\0nep\0nld\0nor\0oci\0orm\0ori\0"
  102. "pan\0pol\0pus\0por\0que\0roh\0run\0ron\0rus\0kin\0"
  103. "san\0snd\0sag\0srp\0sin\0slk\0slv\0smo\0sna\0som\0sqi\0srp\0ssw\0sot\0sun\0swe\0swa\0"
  104. "tat\0tel\0tgk\0tha\0tir\0tuk\0tgl\0tsn\0ton\0tur\0tsn\0tat\0twi\0"
  105. "uig\0ukr\0urd\0uzb\0vie\0vol\0wol\0xho\0yid\0yor\0zha\0zho\0zul";
  106. /* This list MUST contain a three-letter code for every two-letter code in the
  107.    list above, and they MUST ne in the same order (i.e., the same language must
  108.    be in the same place in both lists)! */
  109.  
  110. static const char _countries[] =
  111. "AD\0AE\0AF\0AG\0AI\0AL\0AM\0AN\0AO\0AQ\0AR\0AS\0AT\0AU\0AW\0AZ\0"
  112. "BA\0BB\0BD\0BE\0BF\0BG\0BH\0BI\0BJ\0BM\0BN\0BO\0BR\0BS\0BT\0BV\0BW\0BY\0BZ\0"
  113. "CA\0CC\0CF\0CG\0CH\0CI\0CK\0CL\0CM\0CN\0CO\0CR\0CU\0CV\0CX\0CY\0CZ\0"
  114. "DE\0DJ\0DK\0DM\0DO\0DZ\0EC\0EE\0EG\0EH\0ER\0ES\0ET\0"
  115. "FI\0FJ\0FK\0FM\0FO\0FR\0FX\0"
  116. "GA\0GB\0GD\0GE\0GF\0GH\0GI\0GL\0GM\0GN\0GP\0GQ\0GR\0GS\0GT\0GU\0GW\0GY\0"
  117. "HK\0HM\0HN\0HR\0HT\0HU\0ID\0IE\0IL\0IN\0IO\0IQ\0IR\0IS\0IT\0"
  118. "JM\0JO\0JP\0KE\0KG\0KH\0KI\0KM\0KN\0KP\0KR\0KW\0KY\0KZ\0"
  119. "LA\0LB\0LC\0LI\0LK\0LR\0LS\0LT\0LU\0LV\0LY\0"
  120. "MA\0MC\0MD\0MG\0MH\0MK\0ML\0MM\0MN\0MO\0MP\0MQ\0MR\0MS\0MT\0MU\0MV\0MW\0MX\0MY\0MZ\0"
  121. "NA\0NC\0NE\0NF\0NG\0NI\0NL\0NO\0NP\0NR\0NU\0NZ\0OM\0"
  122. "PA\0PE\0PF\0PG\0PH\0PK\0PL\0PM\0PN\0PR\0PT\0PW\0PY\0QA\0RE\0RO\0RU\0RW\0"
  123. "SA\0SB\0SC\0SD\0SE\0SG\0SH\0SI\0SJ\0SK\0SL\0SM\0SN\0SO\0SR\0ST\0SV\0SY\0SZ\0"
  124. "TC\0TD\0TF\0TG\0TH\0TJ\0TK\0TM\0TN\0TO\0TP\0TR\0TT\0TV\0TW\0TZ\0"
  125. "UA\0UG\0UM\0US\0UY\0UZ\0VA\0VC\0VE\0VG\0VI\0VN\0VU\0"
  126. "WF\0WS\0YE\0YT\0YU\0ZA\0ZM\0ZR\0ZW";
  127. /* This list MUST be in sorted order, and MUST contain only two-letter codes! */
  128.  
  129. static const char _countries3[] =
  130. "AND\0ARE\0AFG\0ATG\0AIA\0ALB\0ARM\0ANT\0AGO\0ATA\0ARG\0ASM\0AUT\0AUS\0ABW\0AZE\0"
  131. "BIH\0BRB\0BGD\0BEL\0BFA\0BGR\0BHR\0BDI\0BEN\0BMU\0BRN\0BOL\0BRA\0BHS\0BTN\0BVT\0BWA"
  132. "\0BLR\0BLZ\0"
  133. "CAN\0CCK\0CAF\0COG\0CHE\0CIV\0COK\0CHL\0CMR\0CHN\0COL\0CRI\0CUB\0CPV\0CXR\0CYP\0CZE\0"
  134. "DEU\0DJI\0DNK\0DMA\0DOM\0DZA\0ECU\0EST\0EGY\0ESH\0ERI\0ESP\0ETH\0"
  135. "FIN\0FJI\0FLK\0FSM\0FRO\0FRA\0FXX\0"
  136. "GAB\0GBR\0GRD\0GEO\0GUF\0GHA\0GIB\0GRL\0GMB\0GIN\0GLP\0GNQ\0GRC\0SGS\0GTM\0GUM"
  137. "\0GNB\0GUY\0"
  138. "HKG\0HMD\0HND\0HRV\0HTI\0HUN\0IDN\0IRL\0ISR\0IND\0IOT\0IRQ\0IRN\0ISL\0ITA\0"
  139. "JAM\0JOR\0JPN\0KEN\0KGZ\0KHM\0KIR\0COM\0KNA\0PRK\0KOR\0KWT\0CYM\0KAZ\0"
  140. "LAO\0LBN\0LCA\0LIE\0LKA\0LBR\0LSO\0LTU\0LUX\0LVA\0LBY\0"
  141. "MAR\0MCO\0MDA\0MDG\0MHL\0MKD\0MLI\0MMR\0MNG\0MAC\0MNP\0MTQ\0MRT\0MSR\0MLT\0MUS\0"
  142. "MDV\0MWI\0MEX\0MYS\0MOZ\0"
  143. "NAM\0NCL\0NER\0NFK\0NGA\0NIC\0NLD\0NOR\0NPL\0NRU\0NIU\0NZL\0OMN\0"
  144. "PAN\0PER\0PYF\0PNG\0PHL\0PAK\0POL\0SPM\0PCN\0PRI\0PRT\0PLW\0PRY\0QAT\0REU\0ROM"
  145. "\0RUS\0RWA\0"
  146. "SAU\0SLB\0SYC\0SDN\0SWE\0SGP\0SHN\0SVN\0SJM\0SVK\0SLE\0SMR\0SEN\0SOM\0SUR\0STP"
  147. "\0SLV\0SYR\0SWZ\0"
  148. "TCA\0TCD\0ATF\0TGO\0THA\0TJK\0TKL\0TKM\0TUN\0TON\0TMP\0TUR\0TTO\0TUV\0TWN\0TZA\0"
  149. "UKR\0UGA\0UMI\0USA\0URY\0UZB\0VAT\0VCT\0VEN\0VGB\0VIR\0VNM\0VUT\0"
  150. "WLF\0WSM\0YEM\0MYT\0YUG\0ZAF\0ZMB\0ZAR\0ZWE";
  151. /* This list MUST contain a three-letter code for every two-letter code in
  152.    the above list, and they MUST be listed in the same order! */
  153.  
  154. static char** _isoLanguages = NULL;
  155. static char** _isoCountries = NULL;
  156.  
  157. /*******************************************************************************
  158.   Implementation function definitions
  159. *******************************************************************************/
  160.  
  161. static int16_t _findIndex(const char* list, int32_t listLength, const char* key);
  162.  
  163. /*Works like strchr with '_' pr '-'*/
  164. static const char* _findCharSeparator(const char* string);
  165.  
  166. /*Lazy evaluated the list of installed locales*/
  167. static void _lazyEvaluate_installedLocales();
  168.  
  169. /*returns TRUE if a is an ID separator FALSE otherwise*/
  170. #define _isIDSeparator(a) (a == '_' || a == '-')
  171.  
  172.  
  173. /*******************************************************************************
  174.   API function definitions
  175. *******************************************************************************/
  176.  
  177.  
  178. const char* _findCharSeparator(const char* string)
  179. {
  180.   if (string == NULL) return NULL;
  181.   /*Keeps iterating until an ID separator is found*/
  182.   while (*string && !_isIDSeparator(*string)) string++;
  183.   if (*string) return string;
  184.   else return NULL;
  185. }
  186.  
  187.  
  188. int16_t _findIndex(const char* list, int32_t listLength, const char* key)
  189. {
  190.   const char* anchor = list;
  191.   const char* listEnd = anchor + listLength;
  192.   bool_t found = FALSE;
  193.   int index = 0;
  194.   int tokenSize = icu_strlen(list)+1; /*gets the size of the tokens*/
  195.   
  196.   while (!found && list<listEnd)
  197.     {
  198.       if (icu_strcmp(key, list) == 0) 
  199.     {
  200.       found = TRUE;
  201.       break;
  202.     }
  203.       list += tokenSize;
  204.     }
  205.   if (found == TRUE) return ((list - anchor)/tokenSize);
  206.   else return -1;
  207. }
  208.  
  209. const char* uloc_getDefault()
  210. {
  211.   const char* result = _defaultLocale;
  212.   UErrorCode err = U_ZERO_ERROR;
  213.   
  214.   /*lazy evaluates _defaultLocale*/
  215.   if (result == NULL) 
  216.     {
  217.       uloc_setDefault(NULL, &err);
  218.       result = _defaultLocale;
  219.     }
  220.   
  221.   return result;
  222. }
  223.  
  224. void uloc_setDefault(const char*   newDefaultLocale,
  225.              UErrorCode* err) 
  226. {
  227.  
  228.   if (U_FAILURE(*err))    return;
  229.   /* the error code isn't currently used for anything by this function*/
  230.   
  231.   if (newDefaultLocale == NULL) 
  232.     {
  233.       newDefaultLocale = icu_getDefaultLocaleID();
  234.     }
  235.   
  236.   umtx_lock(NULL);
  237.   if(_defaultLocale == NULL)
  238.     _defaultLocale = (char*)icu_malloc(sizeof(char) * (icu_strlen(newDefaultLocale) + 1));
  239.   else
  240.     _defaultLocale = (char*)icu_realloc(_defaultLocale, 
  241.                          sizeof(char) * (icu_strlen(newDefaultLocale) + 1));
  242.   icu_strcpy(_defaultLocale, newDefaultLocale);
  243.   umtx_unlock(NULL);
  244.  
  245.   /* propagate change to C++ */
  246.   locale_set_default(newDefaultLocale);
  247. }
  248.  
  249.  
  250. int32_t uloc_getParent(const char*    localeID,
  251.                char* parent,
  252.                int32_t parentCapacity,
  253.                UErrorCode* err)
  254. {
  255.   int i=0;
  256.   int offset = 0;
  257.   int count = 0;
  258.  
  259.   if (U_FAILURE(*err)) return 0;
  260.  
  261.   if (localeID == NULL)    localeID = uloc_getDefault();
  262.   
  263.  
  264.  while (localeID[offset]&&(count < 2))
  265.     {
  266.       if (_isIDSeparator(localeID[offset++])) count++;
  267.     }
  268.   
  269.   /*finds the second IDSeparator*/
  270.   while (offset && !_isIDSeparator(localeID[offset])) offset--;
  271.  
  272.   
  273.   /*Loop updates i to the size of the parent
  274.     but only copies into the buffer as much as the buffer can bare*/
  275.   while (i < offset)
  276.     {
  277.       if (parentCapacity > i) parent[i] = localeID[i];
  278.       i++;
  279.     }
  280.   
  281.   /*Sets the error code on case of need*/
  282.   if (i >= parentCapacity )
  283.     {
  284.       *err = U_BUFFER_OVERFLOW_ERROR;
  285.     }
  286.   
  287.   if (parentCapacity>0)   parent[icu_min(i,parentCapacity-1)] = '\0';
  288.  
  289.   
  290.   return i+1;
  291. }
  292.  
  293. int32_t
  294. uloc_getLanguage(const char*    localeID,
  295.          char* language,
  296.          int32_t languageCapacity,
  297.          UErrorCode* err)
  298. {
  299.   int i=0;
  300.   
  301.   
  302.   if (U_FAILURE(*err)) return 0;
  303.   
  304.   if (localeID == NULL)    localeID = uloc_getDefault();
  305.  
  306.   /*Loop updates i to the size of the language
  307.     but only copies into the buffer as much as the buffer can bare*/
  308.   while ((*localeID != '\0') && !_isIDSeparator(*localeID))
  309.     {
  310.       if (languageCapacity > i) language[i] = tolower(*localeID);
  311.       i++;
  312.       localeID++;
  313.     }
  314.   
  315.   if (i >= languageCapacity )
  316.     {
  317.       *err = U_BUFFER_OVERFLOW_ERROR;
  318.     }
  319.   
  320.   if (languageCapacity > 0) 
  321.     {
  322.       language[icu_min(i,languageCapacity-1)] = '\0';
  323.       /*We need to normalize for changes in ISO language names,
  324.         We special case out the recent ISO changes, translating them
  325.         internally to the old iso codes.*/
  326.       if (U_SUCCESS(*err))
  327.     {
  328.       if (icu_strcmp("he", language) == 0) icu_strcpy(language, "iw");
  329.       else if (icu_strcmp("yi", language) == 0) icu_strcpy(language, "ji");
  330.       else if (icu_strcmp("id", language) == 0) icu_strcpy(language, "in");
  331.     }
  332.     }
  333.   
  334.   return i+1;
  335. }
  336.  
  337.  
  338. int32_t uloc_getCountry(const char* localeID,
  339.             char* country,
  340.             int32_t countryCapacity,
  341.             UErrorCode* err) 
  342. {
  343.   int i=0;
  344.   
  345.   if (U_FAILURE(*err)) return 0;
  346.   if (localeID == NULL)    localeID = uloc_getDefault();
  347.   
  348.   localeID = _findCharSeparator(localeID);
  349.   
  350.   /*Loop updates i to the size of the language
  351.     but only copies into the buffer as much as the buffer can bare*/
  352.   if (localeID)
  353.     {
  354.       ++localeID;
  355.       while ((*localeID != '\0') && !_isIDSeparator(*localeID))
  356.       {
  357.         if (countryCapacity > i) country[i] = toupper(*localeID);
  358.         i++;
  359.         localeID++;
  360.       }
  361.     }
  362.   
  363.   if (i >= countryCapacity )
  364.     {
  365.       *err = U_BUFFER_OVERFLOW_ERROR;
  366.     }
  367.   
  368.   if (countryCapacity > 0) {country[icu_min(i,countryCapacity-1)] = '\0';}
  369.   return i+1;
  370. }
  371.  
  372. int32_t uloc_getVariant(const char* localeID,
  373.                         char* variant,
  374.                         int32_t variantCapacity,
  375.                         UErrorCode* err) 
  376. {
  377.   int i=0;
  378.   
  379.   if (U_FAILURE(*err)) return 0;
  380.   if (localeID == NULL)    localeID = uloc_getDefault();
  381.   
  382.   localeID = _findCharSeparator(localeID);
  383.   if (localeID)    localeID = _findCharSeparator(++localeID);
  384.   
  385.   if (localeID)
  386.     {
  387.       ++localeID;
  388.       /*Loop updates i to the size of the language
  389.     but only copies into the buffer as much as the buffer can bare*/
  390.       while (*localeID != '\0')
  391.     {
  392.       if (variantCapacity > i) variant[i] = toupper(*localeID);
  393.       i++;
  394.       localeID++;
  395.     }
  396.       
  397.     }
  398.   
  399.   if (i >= variantCapacity )
  400.     {
  401.       *err = U_BUFFER_OVERFLOW_ERROR;
  402.     }
  403.   
  404.   
  405.   if (variantCapacity>0) {variant[icu_min(i,variantCapacity-1)] = '\0';}
  406.   return i+1;
  407. }
  408.  
  409. int32_t uloc_getName(const char* localeID,
  410.              char* name,
  411.              int32_t nameCapacity,
  412.              UErrorCode* err)  
  413. {
  414.   int i= 0;
  415.   int varSze = 0;
  416.   int cntSze = 0;
  417.   UErrorCode int_err = U_ZERO_ERROR;
  418.   
  419.   if (U_FAILURE(*err)) return 0;
  420.   /*First we preflight the components in order to ensure a valid return value*/
  421.   if (localeID == NULL)    localeID = uloc_getDefault();
  422.  
  423.   cntSze = uloc_getCountry(localeID, 
  424.                NULL , 
  425.                0,
  426.                &int_err);
  427.   int_err = U_ZERO_ERROR;
  428.   varSze = uloc_getVariant(localeID, 
  429.                NULL , 
  430.                0,
  431.                &int_err);
  432.   
  433.   int_err = U_ZERO_ERROR;
  434.   i = uloc_getLanguage(localeID, 
  435.                NULL,
  436.                0, 
  437.                &int_err);
  438.   /*Adjust for the zero terminators*/
  439.   --varSze; 
  440.   --cntSze;
  441.  
  442.   if (cntSze) i++;
  443.   if (varSze) i++;
  444.   i += cntSze + varSze;
  445.   
  446.   int_err = U_ZERO_ERROR;
  447.   
  448.   uloc_getLanguage(localeID, 
  449.            name,
  450.            nameCapacity, 
  451.            &int_err);
  452.  
  453.   /*We fill in the users buffer*/
  454.   if ((nameCapacity>0) && cntSze)
  455.     {
  456.       if (U_SUCCESS(int_err)) icu_strcat(name, "_");
  457.       
  458.       uloc_getCountry(localeID,
  459.           name + icu_strlen(name),
  460.               nameCapacity - icu_strlen(name),
  461.               &int_err);
  462.       
  463.       if (varSze)
  464.     {
  465.       if (U_SUCCESS(int_err)) icu_strcat(name, "_");
  466.       
  467.       uloc_getVariant(localeID,
  468.                    name + icu_strlen(name),
  469.                    nameCapacity - icu_strlen(name), 
  470.                    &int_err);
  471.     }
  472.       
  473.     }
  474.   *err  = int_err;
  475.   
  476.   return i;
  477. }
  478.  
  479. const char* uloc_getISO3Language(const char* localeID) 
  480. {
  481.   int16_t index;
  482.   char lang[TEMPBUFSIZE];
  483.   UErrorCode err = U_ZERO_ERROR;
  484.   
  485.   if (localeID == NULL)    localeID = uloc_getDefault();
  486.   uloc_getLanguage(localeID, lang, TEMPBUFSIZE, &err);
  487.   if (U_FAILURE(err)) return "";
  488.   index = _findIndex(_languages, sizeof(_languages),lang);
  489.   if (index < 0) return "";
  490.   return &(_languages3[index * 4]);
  491. }
  492.  
  493. const char* uloc_getISO3Country(const char* localeID) 
  494. {
  495.   int16_t index;
  496.   char cntry[TEMPBUFSIZE];
  497.   UErrorCode err = U_ZERO_ERROR;
  498.   
  499.   if (localeID == NULL)    localeID = uloc_getDefault();
  500.   uloc_getCountry(localeID, cntry, TEMPBUFSIZE, &err);
  501.   if (U_FAILURE(err)) return "";
  502.   index = _findIndex(_countries, sizeof(_countries), cntry);
  503.   if (index < 0) return "";
  504.  
  505.   return &(_countries3[index * 4]);
  506. }
  507.  
  508. uint32_t uloc_getLCID(const char* localeID) 
  509. {
  510.   UErrorCode err = U_ZERO_ERROR;
  511.   char temp[30];
  512.   const UChar* lcid = NULL;
  513.   uint32_t result = 0;
  514.   UResourceBundle* bundle = ures_open(uloc_getDataDirectory(), localeID, &err);
  515.   
  516.   if (U_SUCCESS(err))
  517.     {
  518.       lcid = ures_get(bundle, _kLocaleID, &err);
  519.       ures_close(bundle);
  520.       if (U_FAILURE(err) || !lcid || u_strlen(lcid) == 0)    
  521.     {
  522.       return 0;
  523.     }
  524.       u_austrcpy(temp, lcid);
  525.       result = (uint32_t)T_CString_stringToInteger(temp, 16);
  526.     }
  527.  
  528.   return result;
  529. }
  530.  
  531. int32_t uloc_getDisplayLanguage(const char* locale,
  532.                 const char* inLocale,
  533.                 UChar* language,
  534.                 int32_t languageCapacity,
  535.                 UErrorCode* status) 
  536. {    
  537.   const UChar* result = NULL;
  538.   int32_t i = 0;
  539.   int langBufSize;
  540.   bool_t doneDefaultLocale = FALSE;
  541.   char inLanguageBuffer[TEMPBUFSIZE];
  542.   char inLocaleBuffer[TEMPBUFSIZE];
  543.   UErrorCode err = U_ZERO_ERROR;
  544.   UResourceBundle* bundle;
  545.   const UChar* temp = NULL;  
  546.   bool_t isDefaultLocale = FALSE;
  547.   const char* dataDir = uloc_getDataDirectory();
  548.   bool_t done = FALSE;
  549.  
  550.   if (U_FAILURE(*status)) return 0;
  551.   
  552.   if (inLocale == NULL)    
  553.     {
  554.       inLocale = uloc_getDefault();
  555.       isDefaultLocale = TRUE;
  556.     }
  557.   else if (icu_strcmp(inLocale, uloc_getDefault()) == 0) isDefaultLocale = TRUE;
  558.   /*truncates the fallback mechanism if we start out with a defaultLocale*/
  559.   
  560.   if (locale == NULL) locale = uloc_getDefault();
  561.   
  562.   /*extracts the language*/
  563.   langBufSize = uloc_getLanguage(locale,
  564.                  inLanguageBuffer,
  565.                  TEMPBUFSIZE,
  566.                  &err);  
  567.  
  568.   
  569.  
  570.   /*We need to implement a fallback mechanism here because we are getting keys out of a
  571.     tagged array, there is no capability of doing this with fallback through the resource
  572.     bundle API*/
  573.   
  574.   if (langBufSize > 1)
  575.     {
  576.       do 
  577.     {    
  578.       /*
  579.         If we are at the root locale ("")
  580.         The first time we fall back to the full default locale
  581.         As we iterate down the latter, if we hit the root locale ("")
  582.         we pass it to the resource bundle api so it checks default.txt
  583.       */
  584.       
  585.       if (inLocale[0] == '\0')
  586.         {
  587.           if (!isDefaultLocale)
  588.         {
  589.           isDefaultLocale = TRUE;
  590.           inLocale = uloc_getDefault();
  591.         }
  592.           else   done = TRUE;
  593.         }
  594.       
  595.       
  596.       bundle = ures_open(dataDir, inLocale, &err);
  597.       
  598.       if (U_SUCCESS(err))
  599.         {
  600.           UErrorCode err = U_ZERO_ERROR;
  601.           temp = ures_getTaggedArrayItem(bundle,
  602.                          _kLanguages,
  603.                          inLanguageBuffer, 
  604.                          &err);
  605.           if (U_SUCCESS(err))        result = temp;
  606.           ures_close(bundle);      
  607.           }
  608.  
  609.  
  610.       err = U_ZERO_ERROR;
  611.  
  612.       /*Iterates down the Locale ID*/
  613.  
  614.       uloc_getParent(inLocale, inLocaleBuffer, TEMPBUFSIZE, &err);
  615.       inLocale = inLocaleBuffer;
  616.  
  617.     } while ((result == NULL) && !done);
  618.     } 
  619.   
  620.  
  621.   if (result)
  622.     {
  623.       i = u_strlen(result)+1;
  624.       if (i > languageCapacity)
  625.     {
  626.       *status = U_BUFFER_OVERFLOW_ERROR;
  627.       
  628.       if (languageCapacity >= 1) 
  629.         {
  630.           u_strncpy(language, result, languageCapacity-1);
  631.           language[languageCapacity-1] = (UChar)0x0000;
  632.         }
  633.     }
  634.       else u_strcpy(language, result);
  635.     }
  636.   else 
  637.     {
  638.       /*Falls back to ISO Name*/
  639.       i = langBufSize;
  640.       if (i > languageCapacity)
  641.     {
  642.       *status = U_BUFFER_OVERFLOW_ERROR;
  643.       
  644.       if (languageCapacity >= 1) 
  645.         {
  646.          
  647.           language[languageCapacity-1] = (UChar)0x0000;
  648.            u_uastrncpy(language, inLanguageBuffer, languageCapacity-1);
  649.         }
  650.     }
  651.       else u_uastrcpy(language, inLanguageBuffer);
  652.     }
  653.   return i;
  654. }
  655.  
  656. int32_t uloc_getDisplayCountry(const char* locale,
  657.                    const char* inLocale,
  658.                    UChar* country,
  659.                    int32_t countryCapacity,
  660.                    UErrorCode* status)
  661. {
  662.   /* NULL may be used to specify the default */
  663.   const UChar* result = NULL;
  664.   int32_t i = 0;
  665.   int cntryBufSize;
  666.   bool_t doneDefaultLocale = FALSE;
  667.   char inCountryBuffer[TEMPBUFSIZE];
  668.   UErrorCode err = U_ZERO_ERROR;
  669.   UResourceBundle* bundle = NULL;
  670.   char inLocaleBuffer[TEMPBUFSIZE];
  671.   bool_t isDefaultLocale = FALSE;
  672.   const char* dataDir = uloc_getDataDirectory();
  673.   bool_t done = FALSE;
  674.  
  675.   if (U_FAILURE(*status)) return 0;
  676.   
  677.   
  678.  
  679.   if (inLocale == NULL)    
  680.     {
  681.       inLocale = uloc_getDefault();
  682.       isDefaultLocale = TRUE;
  683.     }
  684.   else if (icu_strcmp(inLocale, uloc_getDefault()) == 0) isDefaultLocale = TRUE;
  685.     /*truncates the fallback mechanism if we start out with a defaultLocale*/
  686.  
  687.   if (locale == NULL) locale = uloc_getDefault();
  688.   
  689.     /*extracts the country*/
  690.   cntryBufSize = uloc_getCountry(locale, inCountryBuffer, TEMPBUFSIZE, &err);
  691.  
  692.  
  693.   
  694.   if (cntryBufSize > 1)
  695.     {
  696.       /*
  697.     We need to implement a fallback mechanism here because we are getting keys out of a
  698.     tagged array, there is no capability of doing this with fallback through the resource
  699.     bundle API
  700.       */
  701.   do 
  702.     {
  703.       /*
  704.     If we are at the root locale ("")
  705.     The first time we fall back to the full default locale
  706.     As we iterate down the latter, if we hit the root locale ("")
  707.     we pass it to the resource bundle api so it checks default.txt
  708.       */
  709.       
  710.       if (inLocale[0] == '\0')
  711.     {
  712.       if (!isDefaultLocale)
  713.         {
  714.           isDefaultLocale = TRUE;
  715.           inLocale = uloc_getDefault();
  716.         }
  717.       else   done = TRUE;
  718.     }
  719.       
  720.  
  721.       bundle = ures_open(dataDir, inLocale, &err);      
  722.       
  723.       if (U_SUCCESS(err))
  724.     {
  725.       const UChar* temp;
  726.       
  727.       temp = ures_getTaggedArrayItem(bundle,
  728.                      _kCountries,
  729.                      inCountryBuffer, 
  730.                      &err);
  731.       if (U_SUCCESS(err))  
  732.         result = temp;
  733.       ures_close(bundle);
  734.     }
  735.  
  736.       err = U_ZERO_ERROR;
  737.       uloc_getParent(inLocale, inLocaleBuffer, TEMPBUFSIZE, &err);
  738.       
  739.       inLocale = inLocaleBuffer;
  740.     } while ((result == NULL) && !done);
  741.     }
  742.   
  743.   if (result)
  744.     {
  745.       i = u_strlen(result)+1;
  746.       if (i > countryCapacity)
  747.     {
  748.       *status = U_BUFFER_OVERFLOW_ERROR;
  749.  
  750.       if (countryCapacity >= 1)
  751.         {
  752.           country[countryCapacity-1] = (UChar)0x0000;
  753.           u_strncpy(country, result, countryCapacity-1);
  754.         }
  755.     }
  756.       else u_strcpy(country, result);
  757.     }
  758.   else 
  759.     {
  760.       /*Falls back to ISO Name*/
  761.       i = cntryBufSize;
  762.       if (i > countryCapacity)
  763.     {
  764.       *status = U_BUFFER_OVERFLOW_ERROR;
  765.       
  766.       if (countryCapacity >= 1) 
  767.         {
  768.           u_uastrncpy(country, inCountryBuffer, countryCapacity-1);
  769.           country[countryCapacity-1] = (UChar)0x0000;
  770.         }
  771.     }
  772.       else u_uastrcpy(country, inCountryBuffer);
  773.     }
  774.  
  775.   return i;
  776. }
  777.  
  778. int32_t uloc_getDisplayVariant(const char* locale,
  779.                    const char* inLocale,
  780.                    UChar* variant,
  781.                    int32_t variantCapacity,
  782.                    UErrorCode* status)
  783. {
  784.   const UChar* result = NULL;
  785.   int32_t i = 0;
  786.   int varBufSize;
  787.   bool_t doneDefaultLocale = FALSE;
  788.   char inVariantBuffer[TEMPBUFSIZE];
  789.   char* inVariant = inVariantBuffer;
  790.   UErrorCode err = U_ZERO_ERROR;
  791.   UResourceBundle* bundle;
  792.   char inLocaleBuffer[TEMPBUFSIZE];
  793.   bool_t isDefaultLocale = FALSE;
  794.   char inVariantTagBuffer[TEMPBUFSIZE+2];
  795.   char* inVariantTag = inVariantTagBuffer;
  796.   const char* dataDir = uloc_getDataDirectory();
  797.   bool_t done = FALSE;
  798.  
  799.   if (U_FAILURE(*status)) return 0;
  800.   
  801.   inVariantTagBuffer[0] = '\0';
  802.   
  803.   if (inLocale == NULL)    
  804.     {
  805.       inLocale = uloc_getDefault();
  806.       isDefaultLocale = TRUE;
  807.     }
  808.   else if (icu_strcmp(inLocale, uloc_getDefault()) == 0) isDefaultLocale = TRUE;
  809.     /*truncates the fallback mechanism if we start out with a defaultLocale*/
  810.  
  811.   if (locale == NULL) locale = uloc_getDefault();
  812.     
  813.   /*extracts the variant*/
  814.   varBufSize = uloc_getVariant(locale, inVariant, TEMPBUFSIZE, &err);
  815.   
  816.   if (varBufSize > 1)
  817.     {
  818.       /*In case the variant is longer than our stack buffers*/
  819.       if (err == U_BUFFER_OVERFLOW_ERROR)
  820.     {
  821.       inVariant = (char*)icu_malloc(varBufSize*sizeof(char)+1);
  822.       if (inVariant == NULL) goto NO_MEMORY;
  823.       inVariantTag = (char*)icu_malloc(varBufSize*sizeof(char)+icu_strlen("%%")+1);
  824.       if (inVariantTag == NULL) 
  825.         {
  826.           icu_free(inVariant);
  827.           goto NO_MEMORY;
  828.         }
  829.       err = U_ZERO_ERROR;
  830.       uloc_getVariant(locale, inVariant, varBufSize, &err);
  831.     }
  832.       
  833.       icu_strcpy(inVariantTag,"%%");  
  834.       icu_strcat(inVariantTag, inVariant);
  835.       
  836.       /*We need to implement a fallback mechanism here because we are getting keys out of a
  837.     tagged array, there is no capability of doing this with fallback through the resource
  838.     bundle API*/
  839.       do {
  840.       /*
  841.     If we are at the root locale ("")
  842.     The first time we fall back to the full default locale
  843.     As we iterate down the latter, if we hit the root locale ("")
  844.     we pass it to the resource bundle api so it checks default.txt
  845.       */
  846.       
  847.       if (inLocale[0] == '\0')
  848.     {
  849.       if (!isDefaultLocale)
  850.         {
  851.           isDefaultLocale = TRUE;
  852.           inLocale = uloc_getDefault();
  853.         }
  854.       else   done = TRUE;
  855.     }
  856.  
  857.       
  858.       bundle = ures_open(dataDir, inLocale, &err);      
  859.       
  860.       if (U_SUCCESS(err))
  861.     {
  862.       const UChar* temp;
  863.       
  864.       temp = ures_get(bundle,
  865.               inVariantTag, 
  866.               &err);
  867.       if (U_SUCCESS(err))  result = temp;
  868.       ures_close(bundle);
  869.     }
  870.  
  871.       err = U_ZERO_ERROR;
  872.       uloc_getParent(inLocale, inLocaleBuffer, TEMPBUFSIZE, &err);
  873.       
  874.       inLocale = inLocaleBuffer;
  875.     } while ((result == NULL) && !done);
  876.  
  877.  
  878.           
  879.     }
  880.       
  881.       
  882.       if (result)
  883.     {
  884.       i = u_strlen(result)+1;
  885.       if (i > variantCapacity)
  886.     {
  887.       *status = U_BUFFER_OVERFLOW_ERROR;
  888.  
  889.       if (variantCapacity >= 1) 
  890.         {
  891.           variant[variantCapacity-1] = (UChar)0x0000;
  892.           u_strncpy(variant, result, variantCapacity-1);
  893.         }
  894.     }
  895.       else u_strcpy(variant, result);
  896.     }
  897.   else 
  898.     {
  899.       /*Falls back to user's Name*/
  900.       i = varBufSize;
  901.       if (i > variantCapacity)
  902.     {
  903.       *status = U_BUFFER_OVERFLOW_ERROR;
  904.       
  905.       if (variantCapacity >= 1) 
  906.         {
  907.           u_uastrncpy(variant, inVariant, variantCapacity-1);
  908.           variant[variantCapacity-1] = (UChar)0x0000;
  909.         }
  910.     }
  911.       else u_uastrcpy(variant, inVariant);
  912.     }
  913.  
  914.   /*Clean up memory*/
  915.   if (inVariant != inVariantBuffer)
  916.     {
  917.       icu_free(inVariant);
  918.       icu_free(inVariantTag);
  919.     } 
  920.   return i;
  921.  
  922. NO_MEMORY:
  923.   *status = U_MEMORY_ALLOCATION_ERROR;
  924.   return 0;
  925. }
  926.  
  927. int32_t uloc_getDisplayName(const char* locale,
  928.                 const char* inLocale, 
  929.                 UChar* result,
  930.                 int32_t nameCapacity,
  931.                 UErrorCode* err) 
  932. {
  933.   UErrorCode int_err = U_ZERO_ERROR;
  934.   int i = 0;
  935.   int cntSze, varSze;
  936.   bool_t has_lang = TRUE;
  937.   int result_size;
  938.  
  939.   int_err = U_ZERO_ERROR;
  940.  
  941.   /*Preflights all the components*/
  942.   cntSze = uloc_getDisplayCountry(locale, 
  943.                   inLocale,
  944.                   NULL , 
  945.                   0,
  946.                   &int_err);
  947.   int_err = U_ZERO_ERROR;
  948.   varSze = uloc_getDisplayVariant(locale, 
  949.                   inLocale,
  950.                   NULL , 
  951.                   0,
  952.                   &int_err);
  953.   
  954.   int_err = U_ZERO_ERROR;
  955.   i = uloc_getDisplayLanguage(locale, 
  956.                   inLocale,
  957.                   NULL,
  958.                   0, 
  959.                   &int_err);
  960.   /*Decrement duplicative zero-terminators*/
  961.   --varSze;
  962.   --cntSze;
  963.   
  964.   /*Logic below adjusts pre-flight information with additional characters "(", ",", " ", ")"
  965.   when neeed be*/
  966.   if ((i-1 == 0) && (varSze == 0)) /*No language field*/
  967.     {
  968.       has_lang = FALSE;
  969.       i = cntSze+1;
  970.     }
  971.   else if (cntSze)
  972.     {
  973.       if (varSze) i += cntSze + varSze + 5;
  974.       else i += cntSze + 3;
  975.     }
  976.   
  977.   int_err = U_ZERO_ERROR;
  978.   
  979.   result_size = uloc_getDisplayLanguage(locale, 
  980.                     inLocale,
  981.                     result,
  982.                     nameCapacity, 
  983.                     &int_err) - 1;
  984.  
  985.   if (U_SUCCESS(int_err)&&cntSze)
  986.     {
  987.       if (U_SUCCESS(int_err))
  988.     {
  989.       if (has_lang) 
  990.         {
  991.           u_strcat(result, openParen);
  992.           result_size += 2;
  993.         }
  994.       
  995.       result_size += uloc_getDisplayCountry(locale,
  996.                         inLocale,
  997.                         result + result_size,
  998.                         nameCapacity - result_size,
  999.                         &int_err) - 1;
  1000.     }
  1001.       
  1002.       if (varSze)
  1003.     {
  1004.       if (U_SUCCESS(int_err))      
  1005.         {
  1006.           u_strcat(result, comma);
  1007.           result_size += 2;
  1008.           
  1009.           result_size += uloc_getDisplayVariant(locale,
  1010.                             inLocale,
  1011.                             result + result_size,
  1012.                             nameCapacity - result_size, 
  1013.                             &int_err) - 1;
  1014.         }
  1015.     }
  1016.       
  1017.       if (U_SUCCESS(int_err)&&has_lang) u_strcat(result, closeParen);
  1018.     }
  1019.   
  1020.   *err  = int_err;
  1021.   
  1022.   return i;
  1023. }
  1024.  
  1025.  
  1026. /**
  1027.  * Returns a list of all available locales.  The return value is a pointer to
  1028.  * an array of pointers to ULocale objects.  Both this array and the pointers
  1029.  * it contains are owned by ICU and should not be deleted or written through
  1030.  * by the caller.  The array is terminated by a null pointer. RTG
  1031.  */
  1032. U_CAPI UnicodeString** T_ResourceBundle_listInstalledLocales(const char* path, int32_t* numInstalledLocales);
  1033.  
  1034. const char*
  1035. uloc_getAvailable(int32_t index) 
  1036. {
  1037.   
  1038.   if (_installedLocales == NULL) _lazyEvaluate_installedLocales();
  1039.   
  1040.   if (index > _installedLocalesCount) return NULL;
  1041.   else  return _installedLocales[index];
  1042.   
  1043. }
  1044.  
  1045. int32_t uloc_countAvailable()
  1046. {
  1047.   if (_installedLocales == NULL) _lazyEvaluate_installedLocales();
  1048.   
  1049.     return _installedLocalesCount;
  1050. }
  1051.  
  1052. void _lazyEvaluate_installedLocales()
  1053. {
  1054.   UnicodeString** temp;
  1055.   char **  temp2;
  1056.   int i;
  1057.   if (_installedLocales == NULL)
  1058.     {
  1059.       temp = T_ResourceBundle_listInstalledLocales(uloc_getDataDirectory(),
  1060.                            &_installedLocalesCount);
  1061.       temp2 = (char **) icu_malloc(sizeof(char*) * (_installedLocalesCount+1));
  1062.       
  1063.       for (i = 0; i < _installedLocalesCount; i++)
  1064.     {
  1065.       temp2[i] = (char*) icu_malloc(sizeof(char) *
  1066.                         (u_strlen(T_UnicodeString_getUChars(temp[i])) + 1));
  1067.       temp2[i] = u_austrcpy(temp2[i], T_UnicodeString_getUChars(temp[i]));
  1068.     }
  1069.       {
  1070.     umtx_lock(NULL);
  1071.     if (_installedLocales == NULL)
  1072.       {
  1073.         _installedLocales = temp2;
  1074.         temp2 = NULL;
  1075.       }
  1076.     else {
  1077.       for (i = 0; i < _installedLocalesCount; i++) icu_free(temp2[i]);
  1078.       icu_free(temp2);
  1079.     }
  1080.     umtx_unlock(NULL);
  1081.     
  1082.       }
  1083.     }
  1084. }
  1085.  
  1086. /**
  1087.  * Returns a list of all language codes defined in ISO 639.  This is a pointer
  1088.  * to an array of pointers to arrays of char.  All of these pointers are owned
  1089.  * by ICU-- do not delete them, and do not write through them.  The array is
  1090.  * terminated with a null pointer.
  1091.  */
  1092. const char* const* uloc_getISOLanguages() 
  1093. {
  1094.   const char *from, *end;
  1095.   char **to;
  1096.   
  1097.   if (_isoLanguages == NULL) 
  1098.     {
  1099.       
  1100.       {
  1101.     umtx_lock(NULL);
  1102.     
  1103.     if (_isoLanguages == NULL) 
  1104.       {
  1105.         _isoLanguages = (char**) icu_malloc(sizeof(char*)*(1+(sizeof(_languages) / 3)));
  1106.         
  1107.         end = _languages + (sizeof(_languages));
  1108.         from = _languages; 
  1109.         to = _isoLanguages;
  1110.         
  1111.         while (from < end) 
  1112.           {
  1113.         *to = (char*)from;
  1114.         ++to;
  1115.         from += 3;
  1116.           }
  1117.         *to = NULL;
  1118.       }
  1119.     umtx_unlock(NULL);
  1120.       }
  1121.     }
  1122.   return (const char* const*)_isoLanguages;
  1123. }
  1124.  
  1125. /**
  1126.  * Returns a list of all 2-letter country codes defined in ISO 639.  This is a
  1127.  * pointer to an array of pointers to arrays of char.  All of these pointers are
  1128.  * owned by ICU-- do not delete them, and do not write through them.  The array is
  1129.  * terminated with a null pointer.
  1130.  */
  1131. const char* const* uloc_getISOCountries() 
  1132. {
  1133.   if (_isoCountries == NULL) 
  1134.     {
  1135.       const char *from, *end;
  1136.       char **to;
  1137.       {
  1138.     umtx_lock(NULL);
  1139.     
  1140.     if (_isoCountries == NULL) 
  1141.       {
  1142.         _isoCountries = (char**) icu_malloc(sizeof(char*)*(1+(sizeof(_countries) / 3)));
  1143.         
  1144.         end = _countries + (sizeof(_countries));
  1145.         from = _countries;
  1146.         to = _isoCountries;
  1147.         
  1148.         while (from < end) 
  1149.           {
  1150.         *to = (char*)from;
  1151.         ++to;
  1152.         from += 3;
  1153.           }
  1154.         *to = NULL;
  1155.       }
  1156.     umtx_unlock(NULL);
  1157.       }
  1158.     }
  1159.   return (const char* const*)_isoCountries;
  1160. }
  1161.  
  1162. /**
  1163.  * Functions to get and set the directory containing the locale data files.
  1164.  */
  1165.  
  1166. const char*
  1167. uloc_getDataDirectory()
  1168. {
  1169.   if (_dataDirectory == NULL) 
  1170.     {
  1171.       uloc_setDataDirectory(icu_getDefaultDataDirectory());
  1172.     }
  1173.   return _dataDirectory;
  1174. }
  1175.  
  1176. void
  1177. uloc_setDataDirectory(const char* newDirectory) 
  1178. {
  1179.   char* newDataDirectory = (char*) icu_malloc(sizeof(char)*(icu_strlen(newDirectory) + 1));
  1180.   icu_strcpy(newDataDirectory, newDirectory);
  1181.   
  1182.   {
  1183.     umtx_lock(NULL);
  1184.     
  1185.     if(_dataDirectory != NULL)
  1186.       icu_free(_dataDirectory);
  1187.     _dataDirectory = newDataDirectory;
  1188.     if(_installedLocales != NULL)
  1189.       icu_free(_installedLocales);
  1190.     _installedLocales = NULL;
  1191.     umtx_unlock(NULL);
  1192.   }
  1193. }
  1194.