]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/common/uloc.c
ICU-461.12.tar.gz
[apple/icu.git] / icuSources / common / uloc.c
index c1ac14e3951deb51ec179f07f69a47846a8a0c15..64465032ae3a0f38db5ac1ee9d5cbc6f52bb1f6b 100644 (file)
@@ -1,6 +1,6 @@
 /*
 **********************************************************************
-*   Copyright (C) 1997-2008, International Business Machines
+*   Copyright (C) 1997-2010, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 **********************************************************************
 *
 #include "unicode/utypes.h"
 #include "unicode/ustring.h"
 #include "unicode/uloc.h"
-#include "unicode/ures.h"
 
 #include "putilimp.h"
 #include "ustr_imp.h"
 #include "ulocimp.h"
-#include "uresimp.h"
 #include "umutex.h"
 #include "cstring.h"
 #include "cmemory.h"
@@ -61,24 +59,6 @@ locale_getKeywords(const char *localeID,
             UBool valuesToo,
             UErrorCode *status);
 
-/* ### Constants **************************************************/
-
-/* These strings describe the resources we attempt to load from
- the locale ResourceBundle data file.*/
-static const char _kLanguages[]       = "Languages";
-static const char _kScripts[]         = "Scripts";
-static const char _kCountries[]       = "Countries";
-static const char _kVariants[]        = "Variants";
-static const char _kKeys[]            = "Keys";
-static const char _kTypes[]           = "Types";
-static const char _kIndexLocaleName[] = "res_index";
-static const char _kRootName[]        = "root";
-static const char _kIndexTag[]        = "InstalledLocales";
-static const char _kCurrency[]        = "currency";
-static const char _kCurrencies[]      = "Currencies";
-static char** _installedLocales = NULL;
-static int32_t _installedLocalesCount = 0;
-
 /* ### Data tables **************************************************/
 
 /**
@@ -146,7 +126,7 @@ static const char * const LANGUAGES[] = {
     "lah", "lam", "lb",  "lez", "lg",  "li",  "ln",  "lo",  "lol",
     "loz", "lt",  "lu",  "lua", "lui", "lun", "luo", "lus",
     "lv",  "mad", "mag", "mai", "mak", "man", "map", "mas",
-    "mdf", "mdr", "men", "mg",  "mga", "mh",  "mi",  "mic", "min",
+    "mdf", "mdr", "men", "mfe", "mg",  "mga", "mh",  "mi",  "mic", "min",
     "mis", "mk",  "mkh", "ml",  "mn",  "mnc", "mni", "mno",
     "mo",  "moh", "mos", "mr",  "ms",  "mt",  "mul", "mun",
     "mus", "mwl", "mwr", "my",  "myn", "myv", "na",  "nah", "nai", "nap",
@@ -165,7 +145,7 @@ static const char * const LANGUAGES[] = {
     "srn", "srr", "ss",  "ssa", "st",  "su",  "suk", "sus", "sux",
     "sv",  "sw",  "syc", "syr", "ta",  "tai", "te",  "tem", "ter",
     "tet", "tg",  "th",  "ti",  "tig", "tiv", "tk",  "tkl",
-    "tl",  "tlh", "tli", "tmh", "tn",  "to",  "tog", "tpi", "tr",
+    "tl",  "tlh", "tli", "tmh", "tn",  "to",  "tog", "tpi", "tr", "trv",
     "ts",  "tsi", "tt",  "tum", "tup", "tut", "tvl", "tw",
     "ty",  "tyv", "udm", "ug",  "uga", "uk",  "umb", "und", "ur",
     "uz",  "vai", "ve",  "vi",  "vo",  "vot", "wa",  "wak",
@@ -262,8 +242,8 @@ static const char * const LANGUAGES_3[] = {
     "loz", "lit", "lub", "lua", "lui", "lun", "luo", "lus",
 /*  "lv",  "mad", "mag", "mai", "mak", "man", "map", "mas",    */
     "lav", "mad", "mag", "mai", "mak", "man", "map", "mas",
-/*  "mdf", "mdr", "men", "mg",  "mga", "mh",  "mi",  "mic", "min",    */
-    "mdf", "mdr", "men", "mlg", "mga", "mah", "mri", "mic", "min",
+/*  "mdf", "mdr", "men", "mfe", "mg",  "mga", "mh",  "mi",  "mic", "min",    */
+    "mdf", "mdr", "men", "mfe", "mlg", "mga", "mah", "mri", "mic", "min",
 /*  "mis", "mk",  "mkh", "ml",  "mn",  "mnc", "mni", "mno",    */
     "mis", "mkd", "mkh", "mal", "mon", "mnc", "mni", "mno",
 /*  "mo",  "moh", "mos", "mr",  "ms",  "mt",  "mul", "mun",    */
@@ -300,8 +280,8 @@ static const char * const LANGUAGES_3[] = {
     "swe", "swa", "syc", "syr", "tam", "tai", "tel", "tem", "ter",
 /*  "tet", "tg",  "th",  "ti",  "tig", "tiv", "tk",  "tkl",    */
     "tet", "tgk", "tha", "tir", "tig", "tiv", "tuk", "tkl",
-/*  "tl",  "tlh", "tli", "tmh", "tn",  "to",  "tog", "tpi", "tr",     */
-    "tgl", "tlh", "tli", "tmh", "tsn", "ton", "tog", "tpi", "tur",
+/*  "tl",  "tlh", "tli", "tmh", "tn",  "to",  "tog", "tpi", "tr", "trv",    */
+    "tgl", "tlh", "tli", "tmh", "tsn", "ton", "tog", "tpi", "tur", "trv",
 /*  "ts",  "tsi", "tt",  "tum", "tup", "tut", "tvl", "tw",     */
     "tso", "tsi", "tat", "tum", "tup", "tut", "tvl", "twi",
 /*  "ty",  "tyv", "udm", "ug",  "uga", "uk",  "umb", "und", "ur",     */
@@ -481,7 +461,7 @@ typedef struct CanonicalizationMap {
  */
 static const CanonicalizationMap CANONICALIZE_MAP[] = {
     { "",               "en_US_POSIX", NULL, NULL }, /* .NET name */
-    { "C",              "en_US_POSIX", NULL, NULL }, /* POSIX name */
+    { "c",              "en_US_POSIX", NULL, NULL }, /* POSIX name */
     { "posix",          "en_US_POSIX", NULL, NULL }, /* POSIX name (alias of C) */
     { "art_LOJBAN",     "jbo", NULL, NULL }, /* registered name */
     { "az_AZ_CYRL",     "az_Cyrl_AZ", NULL, NULL }, /* .NET name */
@@ -547,12 +527,48 @@ static const VariantMap VARIANT_MAP[] = {
     { "STROKE", "collation", "stroke" }  /* Solaris variant */
 };
 
+/* ### BCP47 Conversion *******************************************/
+/* Test if the locale id has BCP47 u extension and does not have '@' */
+#define _hasBCP47Extension(id) (id && uprv_strstr(id, "@") == NULL && getShortestSubtagLength(localeID) == 1)
+/* Converts the BCP47 id to Unicode id. Does nothing to id if conversion fails */
+#define _ConvertBCP47(finalID, id, buffer, length,err) \
+        if (uloc_forLanguageTag(id, buffer, length, NULL, err) <= 0 || U_FAILURE(*err)) { \
+            finalID=id; \
+        } else { \
+            finalID=buffer; \
+        }
+/* Gets the size of the shortest subtag in the given localeID. */
+static int32_t getShortestSubtagLength(const char *localeID) {
+    int32_t localeIDLength = uprv_strlen(localeID);
+    int32_t length = localeIDLength;
+    int32_t tmpLength = 0;
+    int32_t i;
+    UBool reset = TRUE;
+
+    for (i = 0; i < localeIDLength; i++) {
+        if (localeID[i] != '_' && localeID[i] != '-') {
+            if (reset) {
+                tmpLength = 0;
+                reset = FALSE;
+            }
+            tmpLength++;
+        } else {
+            if (tmpLength != 0 && tmpLength < length) {
+                length = tmpLength;
+            }
+            reset = TRUE;
+        }
+    }
+
+    return length;
+}
+
 /* ### Keywords **************************************************/
 
 #define ULOC_KEYWORD_BUFFER_LEN 25
 #define ULOC_MAX_NO_KEYWORDS 25
 
-static const char * 
+U_CAPI const char * U_EXPORT2
 locale_getKeywordsStart(const char *localeID) {
     const char *result = NULL;
     if((result = uprv_strchr(localeID, '@')) != NULL) {
@@ -807,6 +823,7 @@ uloc_getKeywordValue(const char* localeID,
                      char* buffer, int32_t bufferCapacity,
                      UErrorCode* status)
 { 
+    const char* startSearchHere = NULL;
     const char* nextSeparator = NULL;
     char keywordNameBuffer[ULOC_KEYWORD_BUFFER_LEN];
     char localeKeywordNameBuffer[ULOC_KEYWORD_BUFFER_LEN];
@@ -814,8 +831,16 @@ uloc_getKeywordValue(const char* localeID,
     int32_t result = 0;
 
     if(status && U_SUCCESS(*status) && localeID) {
+      char tempBuffer[ULOC_FULLNAME_CAPACITY];
+      const char* tmpLocaleID;
+
+      if (_hasBCP47Extension(localeID)) {
+          _ConvertBCP47(tmpLocaleID, localeID, tempBuffer, sizeof(tempBuffer), status);
+      } else {
+          tmpLocaleID=localeID;
+      }
     
-      const char* startSearchHere = uprv_strchr(localeID, '@'); /* TODO: REVISIT: shouldn't this be locale_getKeywordsStart ? */
+      startSearchHere = uprv_strchr(tmpLocaleID, '@'); /* TODO: REVISIT: shouldn't this be locale_getKeywordsStart ? */
       if(startSearchHere == NULL) {
           /* no keywords, return at once */
           return 0;
@@ -1087,9 +1112,6 @@ uloc_setKeywordValue(const char* keywordName,
 
 /* ### ID parsing implementation **************************************************/
 
-/*returns TRUE if a is an ID separator FALSE otherwise*/
-#define _isIDSeparator(a) (a == '_' || a == '-')
-
 #define _isPrefixLetter(a) ((a=='x')||(a=='X')||(a=='i')||(a=='I'))
 
 /*returns TRUE if one of the special prefixes is here (s=string)
@@ -1160,7 +1182,7 @@ _copyCount(char *dest, int32_t destCapacity, const char *src) {
     }
 }
 
-static const char* 
+U_CFUNC const char* 
 uloc_getCurrentCountryID(const char* oldID){
     int32_t offset = _findIndex(DEPRECATED_COUNTRIES, oldID);
     if (offset >= 0) {
@@ -1168,7 +1190,7 @@ uloc_getCurrentCountryID(const char* oldID){
     }
     return oldID;
 }
-static const char* 
+U_CFUNC const char* 
 uloc_getCurrentLanguageID(const char* oldID){
     int32_t offset = _findIndex(DEPRECATED_LANGUAGES, oldID);
     if (offset >= 0) {
@@ -1184,10 +1206,10 @@ uloc_getCurrentLanguageID(const char* oldID){
  *
  * TODO try to use this in Locale
  */
-static int32_t
-_getLanguage(const char *localeID,
-             char *language, int32_t languageCapacity,
-             const char **pEnd) {
+U_CFUNC int32_t
+ulocimp_getLanguage(const char *localeID,
+                    char *language, int32_t languageCapacity,
+                    const char **pEnd) {
     int32_t i=0;
     int32_t offset;
     char lang[4]={ 0, 0, 0, 0 }; /* temporary buffer to hold language code for searching */
@@ -1230,10 +1252,10 @@ _getLanguage(const char *localeID,
     return i;
 }
 
-static int32_t
-_getScript(const char *localeID,
-            char *script, int32_t scriptCapacity,
-            const char **pEnd)
+U_CFUNC int32_t
+ulocimp_getScript(const char *localeID,
+                  char *script, int32_t scriptCapacity,
+                  const char **pEnd)
 {
     int32_t idLen = 0;
 
@@ -1268,39 +1290,52 @@ _getScript(const char *localeID,
     return idLen;
 }
 
-static int32_t
-_getCountry(const char *localeID,
-            char *country, int32_t countryCapacity,
-            const char **pEnd)
+U_CFUNC int32_t
+ulocimp_getCountry(const char *localeID,
+                   char *country, int32_t countryCapacity,
+                   const char **pEnd)
 {
-    int32_t i=0;
+    int32_t idLen=0;
     char cnty[ULOC_COUNTRY_CAPACITY]={ 0, 0, 0, 0 };
     int32_t offset;
 
     /* copy the country as far as possible and count its length */
-    while(!_isTerminator(*localeID) && !_isIDSeparator(*localeID)) {
-        if(i<countryCapacity) {
-            country[i]=(char)uprv_toupper(*localeID);
-        }
-        if(i<(ULOC_COUNTRY_CAPACITY-1)) {   /*CWB*/
-            cnty[i]=(char)uprv_toupper(*localeID);
+    while(!_isTerminator(localeID[idLen]) && !_isIDSeparator(localeID[idLen])) {
+        if(idLen<(ULOC_COUNTRY_CAPACITY-1)) {   /*CWB*/
+            cnty[idLen]=(char)uprv_toupper(localeID[idLen]);
         }
-        i++;
-        localeID++;
+        idLen++;
     }
 
-    /* convert 3 character code to 2 character code if possible *CWB*/
-    if(i==3) {
-        offset=_findIndex(COUNTRIES_3, cnty);
-        if(offset>=0) {
-            i=_copyCount(country, countryCapacity, COUNTRIES[offset]);
+    /* the country should be either length 2 or 3 */
+    if (idLen == 2 || idLen == 3) {
+        UBool gotCountry = FALSE;
+        /* convert 3 character code to 2 character code if possible *CWB*/
+        if(idLen==3) {
+            offset=_findIndex(COUNTRIES_3, cnty);
+            if(offset>=0) {
+                idLen=_copyCount(country, countryCapacity, COUNTRIES[offset]);
+                gotCountry = TRUE;
+            }
+        }
+        if (!gotCountry) {
+            int32_t i = 0;
+            for (i = 0; i < idLen; i++) {
+                if (i < countryCapacity) {
+                    country[i]=(char)uprv_toupper(localeID[i]);
+                }
+            }
         }
+        localeID+=idLen;
+    } else {
+        idLen = 0;
     }
 
     if(pEnd!=NULL) {
         *pEnd=localeID;
     }
-    return i;
+
+    return idLen;
 }
 
 /**
@@ -1514,36 +1549,44 @@ uloc_openKeywords(const char* localeID,
     int32_t i=0;
     char keywords[256];
     int32_t keywordsCapacity = 256;
+    char tempBuffer[ULOC_FULLNAME_CAPACITY];
+    const char* tmpLocaleID;
+
     if(status==NULL || U_FAILURE(*status)) {
         return 0;
     }
     
-    if(localeID==NULL) {
-        localeID=uloc_getDefault();
+    if (_hasBCP47Extension(localeID)) {
+        _ConvertBCP47(tmpLocaleID, localeID, tempBuffer, sizeof(tempBuffer), status);
+    } else {
+        if (localeID==NULL) {
+           localeID=uloc_getDefault();
+        }
+        tmpLocaleID=localeID;
     }
 
     /* Skip the language */
-    _getLanguage(localeID, NULL, 0, &localeID);
-    if(_isIDSeparator(*localeID)) {
+    ulocimp_getLanguage(tmpLocaleID, NULL, 0, &tmpLocaleID);
+    if(_isIDSeparator(*tmpLocaleID)) {
         const char *scriptID;
         /* Skip the script if available */
-        _getScript(localeID+1, NULL, 0, &scriptID);
-        if(scriptID != localeID+1) {
+        ulocimp_getScript(tmpLocaleID+1, NULL, 0, &scriptID);
+        if(scriptID != tmpLocaleID+1) {
             /* Found optional script */
-            localeID = scriptID;
+            tmpLocaleID = scriptID;
         }
         /* Skip the Country */
-        if (_isIDSeparator(*localeID)) {
-            _getCountry(localeID+1, NULL, 0, &localeID);
-            if(_isIDSeparator(*localeID)) {
-                _getVariant(localeID+1, *localeID, NULL, 0);
+        if (_isIDSeparator(*tmpLocaleID)) {
+            ulocimp_getCountry(tmpLocaleID+1, NULL, 0, &tmpLocaleID);
+            if(_isIDSeparator(*tmpLocaleID)) {
+                _getVariant(tmpLocaleID+1, *tmpLocaleID, NULL, 0);
             }
         }
     }
 
     /* keywords are located after '@' */
-    if((localeID = locale_getKeywordsStart(localeID)) != NULL) {
-        i=locale_getKeywords(localeID+1, '@', keywords, keywordsCapacity, NULL, 0, NULL, FALSE, status);
+    if((tmpLocaleID = locale_getKeywordsStart(tmpLocaleID)) != NULL) {
+        i=locale_getKeywords(tmpLocaleID+1, '@', keywords, keywordsCapacity, NULL, 0, NULL, FALSE, status);
     }
 
     if(i) {
@@ -1578,7 +1621,9 @@ _canonicalize(const char* localeID,
               UErrorCode* err) {
     int32_t j, len, fieldCount=0, scriptSize=0, variantSize=0, nameCapacity;
     char localeBuffer[ULOC_FULLNAME_CAPACITY];
+    char tempBuffer[ULOC_FULLNAME_CAPACITY];
     const char* origLocaleID;
+    const char* tmpLocaleID;
     const char* keywordAssign = NULL;
     const char* separatorIndicator = NULL;
     const char* addKeyword = NULL;
@@ -1590,14 +1635,20 @@ _canonicalize(const char* localeID,
         return 0;
     }
     
-    if (localeID==NULL) {
-        localeID=uloc_getDefault();
+    if (_hasBCP47Extension(localeID)) {
+        _ConvertBCP47(tmpLocaleID, localeID, tempBuffer, sizeof(tempBuffer), err);
+    } else {
+        if (localeID==NULL) {
+           localeID=uloc_getDefault();
+        }
+        tmpLocaleID=localeID;
     }
-    origLocaleID=localeID;
+
+    origLocaleID=tmpLocaleID;
 
     /* if we are doing a full canonicalization, then put results in
        localeBuffer, if necessary; otherwise send them to result. */
-    if (OPTION_SET(options, _ULOC_CANONICALIZE) &&
+    if (/*OPTION_SET(options, _ULOC_CANONICALIZE) &&*/
         (result == NULL || resultCapacity <  sizeof(localeBuffer))) {
         name = localeBuffer;
         nameCapacity = sizeof(localeBuffer);
@@ -1607,17 +1658,17 @@ _canonicalize(const char* localeID,
     }
 
     /* get all pieces, one after another, and separate with '_' */
-    len=_getLanguage(localeID, name, nameCapacity, &localeID);
+    len=ulocimp_getLanguage(tmpLocaleID, name, nameCapacity, &tmpLocaleID);
 
     if(len == I_DEFAULT_LENGTH && uprv_strncmp(origLocaleID, i_default, len) == 0) {
         const char *d = uloc_getDefault();
         
-        len = uprv_strlen(d);
+        len = (int32_t)uprv_strlen(d);
 
         if (name != NULL) {
             uprv_strncpy(name, d, len);
         }
-    } else if(_isIDSeparator(*localeID)) {
+    } else if(_isIDSeparator(*tmpLocaleID)) {
         const char *scriptID;
 
         ++fieldCount;
@@ -1626,13 +1677,13 @@ _canonicalize(const char* localeID,
         }
         ++len;
 
-        scriptSize=_getScript(localeID+1, name+len, nameCapacity-len, &scriptID);
+        scriptSize=ulocimp_getScript(tmpLocaleID+1, name+len, nameCapacity-len, &scriptID);
         if(scriptSize > 0) {
             /* Found optional script */
-            localeID = scriptID;
+            tmpLocaleID = scriptID;
             ++fieldCount;
             len+=scriptSize;
-            if (_isIDSeparator(*localeID)) {
+            if (_isIDSeparator(*tmpLocaleID)) {
                 /* If there is something else, then we add the _ */
                 if(len<nameCapacity) {
                     name[len]='_';
@@ -1641,29 +1692,39 @@ _canonicalize(const char* localeID,
             }
         }
 
-        if (_isIDSeparator(*localeID)) {
-            len+=_getCountry(localeID+1, name+len, nameCapacity-len, &localeID);
-            if(_isIDSeparator(*localeID)) {
-                ++fieldCount;
-                if(len<nameCapacity) {
-                    name[len]='_';
+        if (_isIDSeparator(*tmpLocaleID)) {
+            const char *cntryID;
+            int32_t cntrySize = ulocimp_getCountry(tmpLocaleID+1, name+len, nameCapacity-len, &cntryID);
+            if (cntrySize > 0) {
+                /* Found optional country */
+                tmpLocaleID = cntryID;
+                len+=cntrySize;
+            }
+            if(_isIDSeparator(*tmpLocaleID)) {
+                /* If there is something else, then we add the _  if we found country before.*/
+                if (cntrySize > 0) {
+                    ++fieldCount;
+                    if(len<nameCapacity) {
+                        name[len]='_';
+                    }
+                    ++len;
                 }
-                ++len;
-                variantSize = _getVariant(localeID+1, *localeID, name+len, nameCapacity-len);
+
+                variantSize = _getVariant(tmpLocaleID+1, *tmpLocaleID, name+len, nameCapacity-len);
                 if (variantSize > 0) {
                     variant = name+len;
                     len += variantSize;
-                    localeID += variantSize + 1; /* skip '_' and variant */
+                    tmpLocaleID += variantSize + 1; /* skip '_' and variant */
                 }
             }
         }
     }
 
     /* Copy POSIX-style charset specifier, if any [mr.utf8] */
-    if (!OPTION_SET(options, _ULOC_CANONICALIZE) && *localeID == '.') {
+    if (!OPTION_SET(options, _ULOC_CANONICALIZE) && *tmpLocaleID == '.') {
         UBool done = FALSE;
         do {
-            char c = *localeID;
+            char c = *tmpLocaleID;
             switch (c) {
             case 0:
             case '@':
@@ -1674,24 +1735,24 @@ _canonicalize(const char* localeID,
                     name[len] = c;
                 }
                 ++len;
-                ++localeID;
+                ++tmpLocaleID;
                 break;
             }
         } while (!done);
     }
 
     /* Scan ahead to next '@' and determine if it is followed by '=' and/or ';'
-       After this, localeID either points to '@' or is NULL */
-    if ((localeID=locale_getKeywordsStart(localeID))!=NULL) {
-        keywordAssign = uprv_strchr(localeID, '=');
-        separatorIndicator = uprv_strchr(localeID, ';');
+       After this, tmpLocaleID either points to '@' or is NULL */
+    if ((tmpLocaleID=locale_getKeywordsStart(tmpLocaleID))!=NULL) {
+        keywordAssign = uprv_strchr(tmpLocaleID, '=');
+        separatorIndicator = uprv_strchr(tmpLocaleID, ';');
     }
 
     /* Copy POSIX-style variant, if any [mr@FOO] */
     if (!OPTION_SET(options, _ULOC_CANONICALIZE) &&
-        localeID != NULL && keywordAssign == NULL) {
+        tmpLocaleID != NULL && keywordAssign == NULL) {
         for (;;) {
-            char c = *localeID;
+            char c = *tmpLocaleID;
             if (c == 0) {
                 break;
             }
@@ -1699,13 +1760,13 @@ _canonicalize(const char* localeID,
                 name[len] = c;
             }
             ++len;
-            ++localeID;
+            ++tmpLocaleID;
         }
     }
 
     if (OPTION_SET(options, _ULOC_CANONICALIZE)) {
         /* Handle @FOO variant if @ is present and not followed by = */
-        if (localeID!=NULL && keywordAssign==NULL) {
+        if (tmpLocaleID!=NULL && keywordAssign==NULL) {
             int32_t posixVariantSize;
             /* Add missing '_' if needed */
             if (fieldCount < 2 || (fieldCount < 3 && scriptSize > 0)) {
@@ -1717,7 +1778,7 @@ _canonicalize(const char* localeID,
                     ++fieldCount;
                 } while(fieldCount<2);
             }
-            posixVariantSize = _getVariantEx(localeID+1, '@', name+len, nameCapacity-len,
+            posixVariantSize = _getVariantEx(tmpLocaleID+1, '@', name+len, nameCapacity-len,
                                              (UBool)(variantSize > 0));
             if (posixVariantSize > 0) {
                 if (variant == NULL) {
@@ -1754,7 +1815,7 @@ _canonicalize(const char* localeID,
             const char* id = CANONICALIZE_MAP[j].id;
             int32_t n = (int32_t)uprv_strlen(id);
             if (len == n && uprv_strncmp(name, id, n) == 0) {
-                if (n == 0 && localeID != NULL) {
+                if (n == 0 && tmpLocaleID != NULL) {
                     break; /* Don't remap "" if keywords present */
                 }
                 len = _copyCount(name, nameCapacity, CANONICALIZE_MAP[j].canonicalID);
@@ -1768,14 +1829,14 @@ _canonicalize(const char* localeID,
     }
 
     if (!OPTION_SET(options, _ULOC_STRIP_KEYWORDS)) {
-        if (localeID!=NULL && keywordAssign!=NULL &&
+        if (tmpLocaleID!=NULL && keywordAssign!=NULL &&
             (!separatorIndicator || separatorIndicator > keywordAssign)) {
             if(len<nameCapacity) {
                 name[len]='@';
             }
             ++len;
             ++fieldCount;
-            len += _getKeywords(localeID+1, '@', name+len, nameCapacity-len, NULL, 0, NULL, TRUE,
+            len += _getKeywords(tmpLocaleID+1, '@', name+len, nameCapacity-len, NULL, 0, NULL, TRUE,
                                 addKeyword, addValue, err);
         } else if (addKeyword != NULL) {
             U_ASSERT(addValue != NULL);
@@ -1841,7 +1902,7 @@ uloc_getLanguage(const char*    localeID,
         localeID=uloc_getDefault();
     }
 
-    i=_getLanguage(localeID, language, languageCapacity, NULL);
+    i=ulocimp_getLanguage(localeID, language, languageCapacity, NULL);
     return u_terminateChars(language, languageCapacity, i, err);
 }
 
@@ -1862,9 +1923,9 @@ uloc_getScript(const char*    localeID,
     }
 
     /* skip the language */
-    _getLanguage(localeID, NULL, 0, &localeID);
+    ulocimp_getLanguage(localeID, NULL, 0, &localeID);
     if(_isIDSeparator(*localeID)) {
-        i=_getScript(localeID+1, script, scriptCapacity, NULL);
+        i=ulocimp_getScript(localeID+1, script, scriptCapacity, NULL);
     }
     return u_terminateChars(script, scriptCapacity, i, err);
 }
@@ -1886,17 +1947,17 @@ uloc_getCountry(const char* localeID,
     }
 
     /* Skip the language */
-    _getLanguage(localeID, NULL, 0, &localeID);
+    ulocimp_getLanguage(localeID, NULL, 0, &localeID);
     if(_isIDSeparator(*localeID)) {
         const char *scriptID;
         /* Skip the script if available */
-        _getScript(localeID+1, NULL, 0, &scriptID);
+        ulocimp_getScript(localeID+1, NULL, 0, &scriptID);
         if(scriptID != localeID+1) {
             /* Found optional script */
             localeID = scriptID;
         }
         if(_isIDSeparator(*localeID)) {
-            i=_getCountry(localeID+1, country, countryCapacity, NULL);
+            i=ulocimp_getCountry(localeID+1, country, countryCapacity, NULL);
         }
     }
     return u_terminateChars(country, countryCapacity, i, err);
@@ -1908,31 +1969,47 @@ uloc_getVariant(const char* localeID,
                 int32_t variantCapacity,
                 UErrorCode* err) 
 {
+    char tempBuffer[ULOC_FULLNAME_CAPACITY];
+    const char* tmpLocaleID;
     int32_t i=0;
     
     if(err==NULL || U_FAILURE(*err)) {
         return 0;
     }
     
-    if(localeID==NULL) {
-        localeID=uloc_getDefault();
+    if (_hasBCP47Extension(localeID)) {
+        _ConvertBCP47(tmpLocaleID, localeID, tempBuffer, sizeof(tempBuffer), err);
+    } else {
+        if (localeID==NULL) {
+           localeID=uloc_getDefault();
+        }
+        tmpLocaleID=localeID;
     }
     
     /* Skip the language */
-    _getLanguage(localeID, NULL, 0, &localeID);
-    if(_isIDSeparator(*localeID)) {
+    ulocimp_getLanguage(tmpLocaleID, NULL, 0, &tmpLocaleID);
+    if(_isIDSeparator(*tmpLocaleID)) {
         const char *scriptID;
         /* Skip the script if available */
-        _getScript(localeID+1, NULL, 0, &scriptID);
-        if(scriptID != localeID+1) {
+        ulocimp_getScript(tmpLocaleID+1, NULL, 0, &scriptID);
+        if(scriptID != tmpLocaleID+1) {
             /* Found optional script */
-            localeID = scriptID;
+            tmpLocaleID = scriptID;
         }
         /* Skip the Country */
-        if (_isIDSeparator(*localeID)) {
-            _getCountry(localeID+1, NULL, 0, &localeID);
-            if(_isIDSeparator(*localeID)) {
-                i=_getVariant(localeID+1, *localeID, variant, variantCapacity);
+        if (_isIDSeparator(*tmpLocaleID)) {
+            const char *cntryID;
+            ulocimp_getCountry(tmpLocaleID+1, NULL, 0, &cntryID);
+            if (cntryID != tmpLocaleID+1) {
+                /* Found optional country */
+                tmpLocaleID = cntryID;
+            }
+            if(_isIDSeparator(*tmpLocaleID)) {
+                /* If there was no country ID, skip a possible extra IDSeparator */
+                if (tmpLocaleID != cntryID && _isIDSeparator(tmpLocaleID[1])) {
+                    tmpLocaleID++;
+                }
+                i=_getVariant(tmpLocaleID+1, *tmpLocaleID, variant, variantCapacity);
             }
         }
     }
@@ -2068,903 +2145,164 @@ uloc_setDefault(const char*   newDefaultLocale,
     locale_set_default(newDefaultLocale);
 }
 
-/* ### Display name **************************************************/
+/**
+ * Returns a list of all language codes defined in ISO 639.  This is a pointer
+ * to an array of pointers to arrays of char.  All of these pointers are owned
+ * by ICU-- do not delete them, and do not write through them.  The array is
+ * terminated with a null pointer.
+ */
+U_CAPI const char* const*  U_EXPORT2
+uloc_getISOLanguages() 
+{
+    return LANGUAGES;
+}
 
-/*
- * Lookup a resource bundle table item with fallback on the table level.
- * Regular resource bundle lookups perform fallback to parent locale bundles
- * and eventually the root bundle, but only for top-level items.
- * This function takes the name of a top-level table and of an item in that table
- * and performs a lookup of both, falling back until a bundle contains a table
- * with this item.
- *
- * Note: Only the opening of entire bundles falls back through the default locale
- * before root. Once a bundle is open, item lookups do not go through the
- * default locale because that would result in a mix of languages that is
- * unpredictable to the programmer and most likely useless.
+/**
+ * Returns a list of all 2-letter country codes defined in ISO 639.  This is a
+ * pointer to an array of pointers to arrays of char.  All of these pointers are
+ * owned by ICU-- do not delete them, and do not write through them.  The array is
+ * terminated with a null pointer.
  */
-static const UChar *
-_res_getTableStringWithFallback(const char *path, const char *locale,
-                              const char *tableKey, const char *subTableKey,
-                              const char *itemKey,
-                              int32_t *pLength,
-                              UErrorCode *pErrorCode)
+U_CAPI const char* const*  U_EXPORT2
+uloc_getISOCountries() 
 {
-/*    char localeBuffer[ULOC_FULLNAME_CAPACITY*4];*/
-    UResourceBundle *rb=NULL, table, subTable;
-    const UChar *item=NULL;
-    UErrorCode errorCode;
-    char explicitFallbackName[ULOC_FULLNAME_CAPACITY] = {0};
-
-    /*
-     * open the bundle for the current locale
-     * this falls back through the locale's chain to root
-     */
-    errorCode=U_ZERO_ERROR;
-    rb=ures_open(path, locale, &errorCode);
-    if(U_FAILURE(errorCode)) {
-        /* total failure, not even root could be opened */
-        *pErrorCode=errorCode;
-        return NULL;
-    } else if(errorCode==U_USING_DEFAULT_WARNING ||
-                (errorCode==U_USING_FALLBACK_WARNING && *pErrorCode!=U_USING_DEFAULT_WARNING)
-    ) {
-        /* set the "strongest" error code (success->fallback->default->failure) */
-        *pErrorCode=errorCode;
-    }
+    return COUNTRIES;
+}
 
-    for(;;){
-        ures_initStackObject(&table);
-        ures_initStackObject(&subTable);
-        ures_getByKeyWithFallback(rb, tableKey, &table, &errorCode);
-        if (subTableKey != NULL) {
-            /*
-            ures_getByKeyWithFallback(&table,subTableKey, &subTable, &errorCode);
-            item = ures_getStringByKeyWithFallback(&subTable, itemKey, pLength, &errorCode);
-            if(U_FAILURE(errorCode)){
-                *pErrorCode = errorCode;
-            }
-            
-            break;*/
-            
-            ures_getByKeyWithFallback(&table,subTableKey, &table, &errorCode);
-        }
-        if(U_SUCCESS(errorCode)){
-            item = ures_getStringByKeyWithFallback(&table, itemKey, pLength, &errorCode);
-            if(U_FAILURE(errorCode)){
-                const char* replacement = NULL;
-                *pErrorCode = errorCode; /*save the errorCode*/
-                errorCode = U_ZERO_ERROR;
-                /* may be a deprecated code */
-                if(uprv_strcmp(tableKey, "Countries")==0){
-                    replacement =  uloc_getCurrentCountryID(itemKey);
-                }else if(uprv_strcmp(tableKey, "Languages")==0){
-                    replacement =  uloc_getCurrentLanguageID(itemKey);
-                }
-                /*pointer comparison is ok since uloc_getCurrentCountryID & uloc_getCurrentLanguageID return the key itself is replacement is not found*/
-                if(replacement!=NULL && itemKey != replacement){
-                    item = ures_getStringByKeyWithFallback(&table, replacement, pLength, &errorCode);
-                    if(U_SUCCESS(errorCode)){
-                        *pErrorCode = errorCode;
-                        break;
-                    }
-                }
-            }else{
-                break;
-            }
-        }
-        
-        if(U_FAILURE(errorCode)){    
 
-            /* still can't figure out ?.. try the fallback mechanism */
-            int32_t len = 0;
-            const UChar* fallbackLocale =  NULL;
-            *pErrorCode = errorCode;
-            errorCode = U_ZERO_ERROR;
+/* this function to be moved into cstring.c later */
+static char gDecimal = 0;
 
-            fallbackLocale = ures_getStringByKeyWithFallback(&table, "Fallback", &len, &errorCode);
-            if(U_FAILURE(errorCode)){
-               *pErrorCode = errorCode;
-                break;
-            }
-            
-            u_UCharsToChars(fallbackLocale, explicitFallbackName, len);
-            
-            /* guard against recursive fallback */
-            if(uprv_strcmp(explicitFallbackName, locale)==0){
-                *pErrorCode = U_INTERNAL_PROGRAM_ERROR;
-                break;
-            }
-            ures_close(rb);
-            rb = ures_open(NULL, explicitFallbackName, &errorCode);
-            if(U_FAILURE(errorCode)){
-                *pErrorCode = errorCode;
-                break;
-            }
-            /* succeeded in opening the fallback bundle .. continue and try to fetch the item */
-        }else{
-            break;
-        }
+static /* U_CAPI */
+double
+/* U_EXPORT2 */
+_uloc_strtod(const char *start, char **end) {
+    char *decimal;
+    char *myEnd;
+    char buf[30];
+    double rv;
+    if (!gDecimal) {
+        char rep[5];
+        /* For machines that decide to change the decimal on you,
+        and try to be too smart with localization.
+        This normally should be just a '.'. */
+        sprintf(rep, "%+1.1f", 1.0);
+        gDecimal = rep[2];
     }
-    /* done with the locale string - ready to close table and rb */
-    ures_close(&subTable);
-    ures_close(&table);
-    ures_close(rb);
-    return item;
-}
 
-static int32_t
-_getStringOrCopyKey(const char *path, const char *locale,
-                    const char *tableKey, 
-                    const char* subTableKey,
-                    const char *itemKey,
-                    const char *substitute,
-                    UChar *dest, int32_t destCapacity,
-                    UErrorCode *pErrorCode) {
-    const UChar *s = NULL;
-    int32_t length = 0;
-
-    if(itemKey==NULL) {
-        /* top-level item: normal resource bundle access */
-        UResourceBundle *rb;
-
-        rb=ures_open(path, locale, pErrorCode);
-        if(U_SUCCESS(*pErrorCode)) {
-            s=ures_getStringByKey(rb, tableKey, &length, pErrorCode);
-            /* see comment about closing rb near "return item;" in _res_getTableStringWithFallback() */
-            ures_close(rb);
-        }
+    if(gDecimal == '.') {
+        return uprv_strtod(start, end); /* fall through to OS */
     } else {
-        /* Language code should not be a number. If it is, set the error code. */
-        if (!uprv_strncmp(tableKey, "Languages", 9) && uprv_strtol(itemKey, NULL, 10)) {
-            *pErrorCode = U_MISSING_RESOURCE_ERROR;
+        uprv_strncpy(buf, start, 29);
+        buf[29]=0;
+        decimal = uprv_strchr(buf, '.');
+        if(decimal) {
+            *decimal = gDecimal;
         } else {
-            /* second-level item, use special fallback */
-            s=_res_getTableStringWithFallback(path, locale,
-                                               tableKey, 
-                                               subTableKey,
-                                               itemKey,
-                                               &length,
-                                               pErrorCode);
+            return uprv_strtod(start, end); /* no decimal point */
         }
-    }
-    if(U_SUCCESS(*pErrorCode)) {
-        int32_t copyLength=uprv_min(length, destCapacity);
-        if(copyLength>0 && s != NULL) {
-            u_memcpy(dest, s, copyLength);
+        rv = uprv_strtod(buf, &myEnd);
+        if(end) {
+            *end = (char*)(start+(myEnd-buf)); /* cast away const (to follow uprv_strtod API.) */
         }
-    } else {
-        /* no string from a resource bundle: convert the substitute */
-        length=(int32_t)uprv_strlen(substitute);
-        u_charsToUChars(substitute, dest, uprv_min(length, destCapacity));
-        *pErrorCode=U_USING_DEFAULT_WARNING;
+        return rv;
     }
-
-    return u_terminateUChars(dest, destCapacity, length, pErrorCode);
 }
 
-static int32_t
-_getDisplayNameForComponent(const char *locale,
-                            const char *displayLocale,
-                            UChar *dest, int32_t destCapacity,
-                            int32_t (*getter)(const char *, char *, int32_t, UErrorCode *),
-                            const char *tag,
-                            UErrorCode *pErrorCode) {
-    char localeBuffer[ULOC_FULLNAME_CAPACITY*4];
-    int32_t length;
-    UErrorCode localStatus;
+typedef struct { 
+    float q;
+    int32_t dummy;  /* to avoid uninitialized memory copy from qsort */
+    char *locale;
+} _acceptLangItem;
 
-    /* argument checking */
-    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
-        return 0;
-    }
+static int32_t U_CALLCONV
+uloc_acceptLanguageCompare(const void *context, const void *a, const void *b)
+{
+    const _acceptLangItem *aa = (const _acceptLangItem*)a;
+    const _acceptLangItem *bb = (const _acceptLangItem*)b;
 
-    if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
-        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
-        return 0;
+    int32_t rc = 0;
+    if(bb->q < aa->q) {
+        rc = -1;  /* A > B */
+    } else if(bb->q > aa->q) {
+        rc = 1;   /* A < B */
+    } else {
+        rc = 0;   /* A = B */
     }
 
-    localStatus = U_ZERO_ERROR;
-    length=(*getter)(locale, localeBuffer, sizeof(localeBuffer), &localStatus);
-    if(U_FAILURE(localStatus) || localStatus==U_STRING_NOT_TERMINATED_WARNING) {
-        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
-        return 0;
-    }
-    if(length==0) {
-        return u_terminateUChars(dest, destCapacity, 0, pErrorCode);
+    if(rc==0) {
+        rc = uprv_stricmp(aa->locale, bb->locale);
     }
 
-    return _getStringOrCopyKey(NULL, displayLocale,
-                               tag, NULL, localeBuffer,
-                               localeBuffer, 
-                               dest, destCapacity,
-                               pErrorCode);
-}
-
-U_CAPI int32_t U_EXPORT2
-uloc_getDisplayLanguage(const char *locale,
-                        const char *displayLocale,
-                        UChar *dest, int32_t destCapacity,
-                        UErrorCode *pErrorCode) {
-    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
-                uloc_getLanguage, _kLanguages, pErrorCode);
-}
-
-U_CAPI int32_t U_EXPORT2
-uloc_getDisplayScript(const char* locale,
-                      const char* displayLocale,
-                      UChar *dest, int32_t destCapacity,
-                      UErrorCode *pErrorCode)
-{
-    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
-                uloc_getScript, _kScripts, pErrorCode);
-}
+#if defined(ULOC_DEBUG)
+    /*  fprintf(stderr, "a:[%s:%g], b:[%s:%g] -> %d\n", 
+    aa->locale, aa->q, 
+    bb->locale, bb->q,
+    rc);*/
+#endif
 
-U_CAPI int32_t U_EXPORT2
-uloc_getDisplayCountry(const char *locale,
-                       const char *displayLocale,
-                       UChar *dest, int32_t destCapacity,
-                       UErrorCode *pErrorCode) {
-    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
-                uloc_getCountry, _kCountries, pErrorCode);
+    return rc;
 }
 
-/*
- * TODO separate variant1_variant2_variant3...
- * by getting each tag's display string and concatenating them with ", "
- * in between - similar to uloc_getDisplayName()
- */
-U_CAPI int32_t U_EXPORT2
-uloc_getDisplayVariant(const char *locale,
-                       const char *displayLocale,
-                       UChar *dest, int32_t destCapacity,
-                       UErrorCode *pErrorCode) {
-    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
-                uloc_getVariant, _kVariants, pErrorCode);
-}
+/* 
+mt-mt, ja;q=0.76, en-us;q=0.95, en;q=0.92, en-gb;q=0.89, fr;q=0.87, iu-ca;q=0.84, iu;q=0.82, ja-jp;q=0.79, mt;q=0.97, de-de;q=0.74, de;q=0.71, es;q=0.68, it-it;q=0.66, it;q=0.63, vi-vn;q=0.61, vi;q=0.58, nl-nl;q=0.55, nl;q=0.53
+*/
 
 U_CAPI int32_t U_EXPORT2
-uloc_getDisplayName(const char *locale,
-                    const char *displayLocale,
-                    UChar *dest, int32_t destCapacity,
-                    UErrorCode *pErrorCode)
+uloc_acceptLanguageFromHTTP(char *result, int32_t resultAvailable, UAcceptResult *outResult,
+                            const char *httpAcceptLanguage,
+                            UEnumeration* availableLocales,
+                            UErrorCode *status)
 {
-    int32_t length, length2, length3 = 0;
-    UBool hasLanguage, hasScript, hasCountry, hasVariant, hasKeywords;
-    UEnumeration* keywordEnum = NULL;
-    int32_t keywordCount = 0;
-    const char *keyword = NULL;
-    int32_t keywordLen = 0;
-    char keywordValue[256];
-    int32_t keywordValueLen = 0;
-
-    /* argument checking */
-    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
-        return 0;
-    }
+    _acceptLangItem *j;
+    _acceptLangItem smallBuffer[30];
+    char **strs;
+    char tmp[ULOC_FULLNAME_CAPACITY +1];
+    int32_t n = 0;
+    const char *itemEnd;
+    const char *paramEnd;
+    const char *s;
+    const char *t;
+    int32_t res;
+    int32_t i;
+    int32_t l = (int32_t)uprv_strlen(httpAcceptLanguage);
+    int32_t jSize;
+    char *tempstr; /* Use for null pointer check */
 
-    if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
-        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
-        return 0;
+    j = smallBuffer;
+    jSize = sizeof(smallBuffer)/sizeof(smallBuffer[0]);
+    if(U_FAILURE(*status)) {
+        return -1;
     }
 
-    /*
-     * if there is a language, then write "language (country, variant)"
-     * otherwise write "country, variant"
-     */
-
-    /* write the language */
-    length=uloc_getDisplayLanguage(locale, displayLocale,
-                                   dest, destCapacity,
-                                   pErrorCode);
-    hasLanguage= length>0;
-
-    if(hasLanguage) {
-        /* append " (" */
-        if(length<destCapacity) {
-            dest[length]=0x20;
+    for(s=httpAcceptLanguage;s&&*s;) {
+        while(isspace(*s)) /* eat space at the beginning */
+            s++;
+        itemEnd=uprv_strchr(s,',');
+        paramEnd=uprv_strchr(s,';');
+        if(!itemEnd) {
+            itemEnd = httpAcceptLanguage+l; /* end of string */
         }
-        ++length;
-        if(length<destCapacity) {
-            dest[length]=0x28;
-        }
-        ++length;
-    }
-
-    if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
-        /* keep preflighting */
-        *pErrorCode=U_ZERO_ERROR;
-    }
-
-    /* append the script */
-    if(length<destCapacity) {
-        length2=uloc_getDisplayScript(locale, displayLocale,
-                                       dest+length, destCapacity-length,
-                                       pErrorCode);
-    } else {
-        length2=uloc_getDisplayScript(locale, displayLocale,
-                                       NULL, 0,
-                                       pErrorCode);
-    }
-    hasScript= length2>0;
-    length+=length2;
-
-    if(hasScript) {
-        /* append ", " */
-        if(length<destCapacity) {
-            dest[length]=0x2c;
-        }
-        ++length;
-        if(length<destCapacity) {
-            dest[length]=0x20;
-        }
-        ++length;
-    }
-
-    if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
-        /* keep preflighting */
-        *pErrorCode=U_ZERO_ERROR;
-    }
-
-    /* append the country */
-    if(length<destCapacity) {
-        length2=uloc_getDisplayCountry(locale, displayLocale,
-                                       dest+length, destCapacity-length,
-                                       pErrorCode);
-    } else {
-        length2=uloc_getDisplayCountry(locale, displayLocale,
-                                       NULL, 0,
-                                       pErrorCode);
-    }
-    hasCountry= length2>0;
-    length+=length2;
-
-    if(hasCountry) {
-        /* append ", " */
-        if(length<destCapacity) {
-            dest[length]=0x2c;
-        }
-        ++length;
-        if(length<destCapacity) {
-            dest[length]=0x20;
-        }
-        ++length;
-    }
-
-    if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
-        /* keep preflighting */
-        *pErrorCode=U_ZERO_ERROR;
-    }
-
-    /* append the variant */
-    if(length<destCapacity) {
-        length2=uloc_getDisplayVariant(locale, displayLocale,
-                                       dest+length, destCapacity-length,
-                                       pErrorCode);
-    } else {
-        length2=uloc_getDisplayVariant(locale, displayLocale,
-                                       NULL, 0,
-                                       pErrorCode);
-    }
-    hasVariant= length2>0;
-    length+=length2;
-
-    if(hasVariant) {
-        /* append ", " */
-        if(length<destCapacity) {
-            dest[length]=0x2c;
-        }
-        ++length;
-        if(length<destCapacity) {
-            dest[length]=0x20;
-        }
-        ++length;
-    }
-
-    keywordEnum = uloc_openKeywords(locale, pErrorCode);
-    
-    for(keywordCount = uenum_count(keywordEnum, pErrorCode); keywordCount > 0 ; keywordCount--){
-          if(U_FAILURE(*pErrorCode)){
-              break;
-          }
-          /* the uenum_next returns NUL terminated string */
-          keyword = uenum_next(keywordEnum, &keywordLen, pErrorCode);
-          if(length + length3 < destCapacity) {
-            length3 += uloc_getDisplayKeyword(keyword, displayLocale, dest+length+length3, destCapacity-length-length3, pErrorCode);
-          } else {
-            length3 += uloc_getDisplayKeyword(keyword, displayLocale, NULL, 0, pErrorCode);
-          }
-          if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
-              /* keep preflighting */
-              *pErrorCode=U_ZERO_ERROR;
-          }
-          keywordValueLen = uloc_getKeywordValue(locale, keyword, keywordValue, 256, pErrorCode);
-          if(keywordValueLen) {
-            if(length + length3 < destCapacity) {
-              dest[length + length3] = 0x3D;
-            }
-            length3++;
-            if(length + length3 < destCapacity) {
-              length3 += uloc_getDisplayKeywordValue(locale, keyword, displayLocale, dest+length+length3, destCapacity-length-length3, pErrorCode);
-            } else {
-              length3 += uloc_getDisplayKeywordValue(locale, keyword, displayLocale, NULL, 0, pErrorCode);
-            }
-            if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
-                /* keep preflighting */
-                *pErrorCode=U_ZERO_ERROR;
-            }
-          }
-          if(keywordCount > 1) {
-            if(length + length3 + 1 < destCapacity && keywordCount) {
-              dest[length + length3]=0x2c;
-              dest[length + length3+1]=0x20;
-            }
-            length3++; /* ',' */
-            length3++; /* ' ' */ 
-          }
-    }
-    uenum_close(keywordEnum);
-
-    hasKeywords = length3 > 0;
-    length += length3;
-
-
-
-    if ((hasScript && !hasCountry)
-        || ((hasScript || hasCountry) && !hasVariant && !hasKeywords)
-        || ((hasScript || hasCountry || hasVariant) && !hasKeywords)
-        || (hasLanguage && !hasScript && !hasCountry && !hasVariant && !hasKeywords))
-    {
-        /* remove ", " or " (" */
-        length-=2;
-    }
-
-    if (hasLanguage && (hasScript || hasCountry || hasVariant || hasKeywords)) {
-        /* append ")" */
-        if(length<destCapacity) {
-            dest[length]=0x29;
-        }
-        ++length;
-    }
-
-    if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
-        /* keep preflighting */
-        *pErrorCode=U_ZERO_ERROR;
-    }
-
-    return u_terminateUChars(dest, destCapacity, length, pErrorCode);
-}
-
-U_CAPI int32_t U_EXPORT2
-uloc_getDisplayKeyword(const char* keyword,
-                       const char* displayLocale,
-                       UChar* dest,
-                       int32_t destCapacity,
-                       UErrorCode* status){
-
-    /* argument checking */
-    if(status==NULL || U_FAILURE(*status)) {
-        return 0;
-    }
-
-    if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
-        *status=U_ILLEGAL_ARGUMENT_ERROR;
-        return 0;
-    }
-
-
-    /* pass itemKey=NULL to look for a top-level item */
-    return _getStringOrCopyKey(NULL, displayLocale,
-                               _kKeys, NULL, 
-                               keyword, 
-                               keyword,      
-                               dest, destCapacity,
-                               status);
-
-}
-
-
-#define UCURRENCY_DISPLAY_NAME_INDEX 1
-
-U_CAPI int32_t U_EXPORT2
-uloc_getDisplayKeywordValue(   const char* locale,
-                               const char* keyword,
-                               const char* displayLocale,
-                               UChar* dest,
-                               int32_t destCapacity,
-                               UErrorCode* status){
-
-
-    char keywordValue[ULOC_FULLNAME_CAPACITY*4];
-    int32_t capacity = ULOC_FULLNAME_CAPACITY*4;
-    int32_t keywordValueLen =0;
-
-    /* argument checking */
-    if(status==NULL || U_FAILURE(*status)) {
-        return 0;
-    }
-
-    if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
-        *status=U_ILLEGAL_ARGUMENT_ERROR;
-        return 0;
-    }
-
-    /* get the keyword value */
-    keywordValue[0]=0;
-    keywordValueLen = uloc_getKeywordValue(locale, keyword, keywordValue, capacity, status);
-
-    /* 
-     * if the keyword is equal to currency .. then to get the display name 
-     * we need to do the fallback ourselves
-     */
-    if(uprv_stricmp(keyword, _kCurrency)==0){
-
-        int32_t dispNameLen = 0;
-        const UChar *dispName = NULL;
-        
-        UResourceBundle *bundle     = ures_open(NULL, displayLocale, status);
-        UResourceBundle *currencies = ures_getByKey(bundle, _kCurrencies, NULL, status);
-        UResourceBundle *currency   = ures_getByKeyWithFallback(currencies, keywordValue, NULL, status);
-        
-        dispName = ures_getStringByIndex(currency, UCURRENCY_DISPLAY_NAME_INDEX, &dispNameLen, status);
-        
-        /*close the bundles */
-        ures_close(currency);
-        ures_close(currencies);
-        ures_close(bundle);
-        
-        if(U_FAILURE(*status)){
-            if(*status == U_MISSING_RESOURCE_ERROR){
-                /* we just want to write the value over if nothing is available */
-                *status = U_USING_DEFAULT_WARNING;
-            }else{
-                return 0;
-            }
-        }
-
-        /* now copy the dispName over if not NULL */
-        if(dispName != NULL){
-            if(dispNameLen <= destCapacity){
-                uprv_memcpy(dest, dispName, dispNameLen * U_SIZEOF_UCHAR);
-                return u_terminateUChars(dest, destCapacity, dispNameLen, status);
-            }else{
-                *status = U_BUFFER_OVERFLOW_ERROR;
-                return dispNameLen;
-            }
-        }else{
-            /* we have not found the display name for the value .. just copy over */
-            if(keywordValueLen <= destCapacity){
-                u_charsToUChars(keywordValue, dest, keywordValueLen);
-                return u_terminateUChars(dest, destCapacity, keywordValueLen, status);
-            }else{
-                 *status = U_BUFFER_OVERFLOW_ERROR;
-                return keywordValueLen;
-            }
-        }
-
-        
-    }else{
-
-        return _getStringOrCopyKey(NULL, displayLocale,
-                                   _kTypes, keyword, 
-                                   keywordValue,
-                                   keywordValue,
-                                   dest, destCapacity,
-                                   status);
-    }
-}
-
-/* ### Get available **************************************************/
-
-static UBool U_CALLCONV uloc_cleanup(void) {
-    char ** temp;
-
-    if (_installedLocales) {
-        temp = _installedLocales;
-        _installedLocales = NULL;
-
-        _installedLocalesCount = 0;
-
-        uprv_free(temp);
-    }
-    return TRUE;
-}
-
-static void _load_installedLocales()
-{
-    UBool   localesLoaded;
-
-    UMTX_CHECK(NULL, _installedLocales != NULL, localesLoaded);
-    
-    if (localesLoaded == FALSE) {
-        UResourceBundle *index = NULL;
-        UResourceBundle installed;
-        UErrorCode status = U_ZERO_ERROR;
-        char ** temp;
-        int32_t i = 0;
-        int32_t localeCount;
-        
-        ures_initStackObject(&installed);
-        index = ures_openDirect(NULL, _kIndexLocaleName, &status);
-        ures_getByKey(index, _kIndexTag, &installed, &status);
-        
-        if(U_SUCCESS(status)) {
-            localeCount = ures_getSize(&installed);
-            temp = (char **) uprv_malloc(sizeof(char*) * (localeCount+1));
-            /* Check for null pointer */
-            if (temp != NULL) {
-                ures_resetIterator(&installed);
-                while(ures_hasNext(&installed)) {
-                    ures_getNextString(&installed, NULL, (const char **)&temp[i++], &status);
-                }
-                temp[i] = NULL;
-
-                umtx_lock(NULL);
-                if (_installedLocales == NULL)
-                {
-                    _installedLocalesCount = localeCount;
-                    _installedLocales = temp;
-                    temp = NULL;
-                    ucln_common_registerCleanup(UCLN_COMMON_ULOC, uloc_cleanup);
-                } 
-                umtx_unlock(NULL);
-
-                uprv_free(temp);
-            }
-        }
-        ures_close(&installed);
-        ures_close(index);
-    }
-}
-
-U_CAPI const char* U_EXPORT2
-uloc_getAvailable(int32_t offset) 
-{
-    
-    _load_installedLocales();
-    
-    if (offset > _installedLocalesCount)
-        return NULL;
-    return _installedLocales[offset];
-}
-
-U_CAPI int32_t  U_EXPORT2
-uloc_countAvailable()
-{
-    _load_installedLocales();
-    return _installedLocalesCount;
-}
-
-/**
- * Returns a list of all language codes defined in ISO 639.  This is a pointer
- * to an array of pointers to arrays of char.  All of these pointers are owned
- * by ICU-- do not delete them, and do not write through them.  The array is
- * terminated with a null pointer.
- */
-U_CAPI const char* const*  U_EXPORT2
-uloc_getISOLanguages() 
-{
-    return LANGUAGES;
-}
-
-/**
- * Returns a list of all 2-letter country codes defined in ISO 639.  This is a
- * pointer to an array of pointers to arrays of char.  All of these pointers are
- * owned by ICU-- do not delete them, and do not write through them.  The array is
- * terminated with a null pointer.
- */
-U_CAPI const char* const*  U_EXPORT2
-uloc_getISOCountries() 
-{
-    return COUNTRIES;
-}
-
-
-/* this function to be moved into cstring.c later */
-static char gDecimal = 0;
-
-static /* U_CAPI */
-double
-/* U_EXPORT2 */
-_uloc_strtod(const char *start, char **end) {
-    char *decimal;
-    char *myEnd;
-    char buf[30];
-    double rv;
-    if (!gDecimal) {
-        char rep[5];
-        /* For machines that decide to change the decimal on you,
-        and try to be too smart with localization.
-        This normally should be just a '.'. */
-        sprintf(rep, "%+1.1f", 1.0);
-        gDecimal = rep[2];
-    }
-
-    if(gDecimal == '.') {
-        return uprv_strtod(start, end); /* fall through to OS */
-    } else {
-        uprv_strncpy(buf, start, 29);
-        buf[29]=0;
-        decimal = uprv_strchr(buf, '.');
-        if(decimal) {
-            *decimal = gDecimal;
-        } else {
-            return uprv_strtod(start, end); /* no decimal point */
-        }
-        rv = uprv_strtod(buf, &myEnd);
-        if(end) {
-            *end = (char*)(start+(myEnd-buf)); /* cast away const (to follow uprv_strtod API.) */
-        }
-        return rv;
-    }
-}
-
-typedef struct { 
-    float q;
-    int32_t dummy;  /* to avoid uninitialized memory copy from qsort */
-    char *locale;
-} _acceptLangItem;
-
-static int32_t U_CALLCONV
-uloc_acceptLanguageCompare(const void *context, const void *a, const void *b)
-{
-    const _acceptLangItem *aa = (const _acceptLangItem*)a;
-    const _acceptLangItem *bb = (const _acceptLangItem*)b;
-
-    int32_t rc = 0;
-    if(bb->q < aa->q) {
-        rc = -1;  /* A > B */
-    } else if(bb->q > aa->q) {
-        rc = 1;   /* A < B */
-    } else {
-        rc = 0;   /* A = B */
-    }
-
-    if(rc==0) {
-        rc = uprv_stricmp(aa->locale, bb->locale);
-    }
-
-#if defined(ULOC_DEBUG)
-    /*  fprintf(stderr, "a:[%s:%g], b:[%s:%g] -> %d\n", 
-    aa->locale, aa->q, 
-    bb->locale, bb->q,
-    rc);*/
-#endif
-
-    return rc;
-}
-
-static ULayoutType
-_uloc_getOrientationHelper(const char* localeId,
-                           const char* key,
-                           UErrorCode *status)
-{
-    ULayoutType result = ULOC_LAYOUT_UNKNOWN;
-
-    if (!U_FAILURE(*status)) {
-        int32_t length = 0;
-        char localeBuffer[ULOC_FULLNAME_CAPACITY];
-
-        uloc_canonicalize(localeId, localeBuffer, sizeof(localeBuffer), status);
-
-        if (!U_FAILURE(*status)) {
-            const UChar* const value =
-                _res_getTableStringWithFallback(
-                    NULL,
-                    localeBuffer,
-                    "layout",
-                    NULL,
-                    key,
-                    &length,
-                    status);
-
-            if (!U_FAILURE(*status) && length != 0) {
-                switch(value[0])
-                {
-                case 0x0062: /* 'b' */
-                    result = ULOC_LAYOUT_BTT;
-                    break;
-                case 0x006C: /* 'l' */
-                    result = ULOC_LAYOUT_LTR;
-                    break;
-                case 0x0072: /* 'r' */
-                    result = ULOC_LAYOUT_RTL;
-                    break;
-                case 0x0074: /* 't' */
-                    result = ULOC_LAYOUT_TTB;
-                    break;
-                default:
-                    *status = U_INTERNAL_PROGRAM_ERROR;
-                    break;
-                }
-            }
-        }
-    }
-
-    return result;
-}
-
-U_DRAFT ULayoutType U_EXPORT2
-uloc_getCharacterOrientation(const char* localeId,
-                             UErrorCode *status)
-{
-    return _uloc_getOrientationHelper(localeId, "characters", status);
-}
-
-/**
- * Get the layout line orientation for the specified locale.
- * 
- * @param localeID locale name
- * @param status Error status
- * @return an enum indicating the layout orientation for lines.
- * @draft ICU 4.0
- */
-U_DRAFT ULayoutType U_EXPORT2
-uloc_getLineOrientation(const char* localeId,
-                        UErrorCode *status)
-{
-    return _uloc_getOrientationHelper(localeId, "lines", status);
-}
-
-/* 
-mt-mt, ja;q=0.76, en-us;q=0.95, en;q=0.92, en-gb;q=0.89, fr;q=0.87, iu-ca;q=0.84, iu;q=0.82, ja-jp;q=0.79, mt;q=0.97, de-de;q=0.74, de;q=0.71, es;q=0.68, it-it;q=0.66, it;q=0.63, vi-vn;q=0.61, vi;q=0.58, nl-nl;q=0.55, nl;q=0.53
-*/
-
-U_CAPI int32_t U_EXPORT2
-uloc_acceptLanguageFromHTTP(char *result, int32_t resultAvailable, UAcceptResult *outResult,
-                            const char *httpAcceptLanguage,
-                            UEnumeration* availableLocales,
-                            UErrorCode *status)
-{
-    _acceptLangItem *j;
-    _acceptLangItem smallBuffer[30];
-    char **strs;
-    char tmp[ULOC_FULLNAME_CAPACITY +1];
-    int32_t n = 0;
-    const char *itemEnd;
-    const char *paramEnd;
-    const char *s;
-    const char *t;
-    int32_t res;
-    int32_t i;
-    int32_t l = (int32_t)uprv_strlen(httpAcceptLanguage);
-    int32_t jSize;
-    char *tempstr; /* Use for null pointer check */
-
-    j = smallBuffer;
-    jSize = sizeof(smallBuffer)/sizeof(smallBuffer[0]);
-    if(U_FAILURE(*status)) {
-        return -1;
-    }
-
-    for(s=httpAcceptLanguage;s&&*s;) {
-        while(isspace(*s)) /* eat space at the beginning */
-            s++;
-        itemEnd=uprv_strchr(s,',');
-        paramEnd=uprv_strchr(s,';');
-        if(!itemEnd) {
-            itemEnd = httpAcceptLanguage+l; /* end of string */
-        }
-        if(paramEnd && paramEnd<itemEnd) { 
-            /* semicolon (;) is closer than end (,) */
-            t = paramEnd+1;
-            if(*t=='q') {
-                t++;
-            }
-            while(isspace(*t)) {
-                t++;
-            }
-            if(*t=='=') {
-                t++;
-            }
-            while(isspace(*t)) {
-                t++;
-            }
-            j[n].q = (float)_uloc_strtod(t,NULL);
-        } else {
-            /* no semicolon - it's 1.0 */
-            j[n].q = 1.0f;
-            paramEnd = itemEnd;
+        if(paramEnd && paramEnd<itemEnd) { 
+            /* semicolon (;) is closer than end (,) */
+            t = paramEnd+1;
+            if(*t=='q') {
+                t++;
+            }
+            while(isspace(*t)) {
+                t++;
+            }
+            if(*t=='=') {
+                t++;
+            }
+            while(isspace(*t)) {
+                t++;
+            }
+            j[n].q = (float)_uloc_strtod(t,NULL);
+        } else {
+            /* no semicolon - it's 1.0 */
+            j[n].q = 1.0f;
+            paramEnd = itemEnd;
         }
         j[n].dummy=0;
         /* eat spaces prior to semi */
@@ -3160,1215 +2498,4 @@ uloc_acceptLanguage(char *result, int32_t resultAvailable,
     return -1;
 }
 
-
-/**
- * This function looks for the localeID in the likelySubtags resource.
- *
- * @param localeID The tag to find.
- * @param buffer A buffer to hold the matching entry
- * @param bufferLength The length of the output buffer
- * @return A pointer to "buffer" if found, or a null pointer if not.
- */
-static const char*  U_CALLCONV
-findLikelySubtags(const char* localeID,
-                  char* buffer,
-                  int32_t bufferLength,
-                  UErrorCode* err) {
-    const char* result = NULL;
-
-    if (!U_FAILURE(*err)) {
-        int32_t resLen = 0;
-        const UChar* s = NULL;
-        UResourceBundle* subtags = ures_openDirect(NULL, "likelySubtags", err);
-        if (!U_FAILURE(*err)) {
-            s = ures_getStringByKey(subtags, localeID, &resLen, err);
-
-            if (U_FAILURE(*err)) {
-                /*
-                 * If a resource is missing, it's not really an error, it's
-                 * just that we don't have any data for that particular locale ID.
-                 */
-                if (*err == U_MISSING_RESOURCE_ERROR) {
-                    *err = U_ZERO_ERROR;
-                }
-            }
-            else if (resLen >= bufferLength) {
-                /* The buffer should never overflow. */
-                *err = U_INTERNAL_PROGRAM_ERROR;
-            }
-            else {
-                u_UCharsToChars(s, buffer, resLen + 1);
-                result = buffer;
-            }
-
-            ures_close(subtags);
-        }
-    }
-
-    return result;
-}
-
-/**
- * Append a tag to a buffer, adding the separator if necessary.  The buffer
- * must be large enough to contain the resulting tag plus any separator
- * necessary. The tag must not be a zero-length string.
- *
- * @param tag The tag to add.
- * @param tagLength The length of the tag.
- * @param buffer The output buffer.
- * @param bufferLength The length of the output buffer.  This is an input/ouput parameter.
- **/
-static void U_CALLCONV
-appendTag(
-    const char* tag,
-    int32_t tagLength,
-    char* buffer,
-    int32_t* bufferLength) {
-
-    if (*bufferLength > 0) {
-        buffer[*bufferLength] = '_';
-        ++(*bufferLength);
-    }
-
-    uprv_memmove(
-        &buffer[*bufferLength],
-        tag,
-        tagLength);
-
-    *bufferLength += tagLength;
-}
-
-/**
- * These are the canonical strings for unknown languages, scripts and regions.
- **/
-static const char* const unknownLanguage = "und";
-static const char* const unknownScript = "Zzzz";
-static const char* const unknownRegion = "ZZ";
-
-/**
- * Create a tag string from the supplied parameters.  The lang, script and region
- * parameters may be NULL pointers. If they are, their corresponding length parameters
- * must be less than or equal to 0.
- *
- * If any of the language, script or region parameters are empty, and the alternateTags
- * parameter is not NULL, it will be parsed for potential language, script and region tags
- * to be used when constructing the new tag.  If the alternateTags parameter is NULL, or
- * it contains no language tag, the default tag for the unknown language is used.
- *
- * If the length of the new string exceeds the capacity of the output buffer, 
- * the function copies as many bytes to the output buffer as it can, and returns
- * the error U_BUFFER_OVERFLOW_ERROR.
- *
- * If an illegal argument is provided, the function returns the error
- * U_ILLEGAL_ARGUMENT_ERROR.
- *
- * Note that this function can return the warning U_STRING_NOT_TERMINATED_WARNING if
- * the tag string fits in the output buffer, but the null terminator doesn't.
- *
- * @param lang The language tag to use.
- * @param langLength The length of the language tag.
- * @param script The script tag to use.
- * @param scriptLength The length of the script tag.
- * @param region The region tag to use.
- * @param regionLength The length of the region tag.
- * @param trailing Any trailing data to append to the new tag.
- * @param trailingLength The length of the trailing data.
- * @param alternateTags A string containing any alternate tags.
- * @param tag The output buffer.
- * @param tagCapacity The capacity of the output buffer.
- * @param err A pointer to a UErrorCode for error reporting.
- * @return The length of the tag string, which may be greater than tagCapacity, or -1 on error.
- **/
-static int32_t U_CALLCONV
-createTagStringWithAlternates(
-    const char* lang,
-    int32_t langLength,
-    const char* script,
-    int32_t scriptLength,
-    const char* region,
-    int32_t regionLength,
-    const char* trailing,
-    int32_t trailingLength,
-    const char* alternateTags,
-    char* tag,
-    int32_t tagCapacity,
-    UErrorCode* err) {
-
-    if (U_FAILURE(*err)) {
-        goto error;
-    }
-    else if (tag == NULL ||
-             tagCapacity <= 0 ||
-             langLength >= ULOC_LANG_CAPACITY ||
-             scriptLength >= ULOC_SCRIPT_CAPACITY ||
-             regionLength >= ULOC_COUNTRY_CAPACITY) {
-        goto error;
-    }
-    else {
-        /**
-         * ULOC_FULLNAME_CAPACITY will provide enough capacity
-         * that we can build a string that contains the language,
-         * script and region code without worrying about overrunning
-         * the user-supplied buffer.
-         **/
-        char tagBuffer[ULOC_FULLNAME_CAPACITY];
-        int32_t tagLength = 0;
-        int32_t capacityRemaining = tagCapacity;
-        UBool regionAppended = FALSE;
-
-        if (langLength > 0) {
-            appendTag(
-                lang,
-                langLength,
-                tagBuffer,
-                &tagLength);
-        }
-        else if (alternateTags == NULL) {
-            /*
-             * Append the value for an unknown language, if
-             * we found no language.
-             */
-            appendTag(
-                unknownLanguage,
-                uprv_strlen(unknownLanguage),
-                tagBuffer,
-                &tagLength);
-        }
-        else {
-            /*
-             * Parse the alternateTags string for the language.
-             */
-            char alternateLang[ULOC_LANG_CAPACITY];
-            int32_t alternateLangLength = sizeof(alternateLang);
-
-            alternateLangLength =
-                uloc_getLanguage(
-                    alternateTags,
-                    alternateLang,
-                    alternateLangLength,
-                    err);
-            if(U_FAILURE(*err) ||
-                alternateLangLength >= ULOC_LANG_CAPACITY) {
-                goto error;
-            }
-            else if (alternateLangLength == 0) {
-                /*
-                 * Append the value for an unknown language, if
-                 * we found no language.
-                 */
-                appendTag(
-                    unknownLanguage,
-                    uprv_strlen(unknownLanguage),
-                    tagBuffer,
-                    &tagLength);
-            }
-            else {
-                appendTag(
-                    alternateLang,
-                    alternateLangLength,
-                    tagBuffer,
-                    &tagLength);
-            }
-        }
-
-        if (scriptLength > 0) {
-            appendTag(
-                script,
-                scriptLength,
-                tagBuffer,
-                &tagLength);
-        }
-        else if (alternateTags != NULL) {
-            /*
-             * Parse the alternateTags string for the script.
-             */
-            char alternateScript[ULOC_SCRIPT_CAPACITY];
-
-            const int32_t alternateScriptLength =
-                uloc_getScript(
-                    alternateTags,
-                    alternateScript,
-                    sizeof(alternateScript),
-                    err);
-
-            if (U_FAILURE(*err) ||
-                alternateScriptLength >= ULOC_SCRIPT_CAPACITY) {
-                goto error;
-            }
-            else if (alternateScriptLength > 0) {
-                appendTag(
-                    alternateScript,
-                    alternateScriptLength,
-                    tagBuffer,
-                    &tagLength);
-            }
-        }
-
-        if (regionLength > 0) {
-            appendTag(
-                region,
-                regionLength,
-                tagBuffer,
-                &tagLength);
-
-            regionAppended = TRUE;
-        }
-        else if (alternateTags != NULL) {
-            /*
-             * Parse the alternateTags string for the region.
-             */
-            char alternateRegion[ULOC_COUNTRY_CAPACITY];
-
-            const int32_t alternateRegionLength =
-                uloc_getCountry(
-                    alternateTags,
-                    alternateRegion,
-                    sizeof(alternateRegion),
-                    err);
-            if (U_FAILURE(*err) ||
-                alternateRegionLength >= ULOC_COUNTRY_CAPACITY) {
-                goto error;
-            }
-            else if (alternateRegionLength > 0) {
-                appendTag(
-                    alternateRegion,
-                    alternateRegionLength,
-                    tagBuffer,
-                    &tagLength);
-
-                regionAppended = TRUE;
-            }
-        }
-
-        {
-            const int32_t toCopy =
-                tagLength >= tagCapacity ? tagCapacity : tagLength;
-
-            /**
-             * Copy the partial tag from our internal buffer to the supplied
-             * target.
-             **/
-            uprv_memcpy(
-                tag,
-                tagBuffer,
-                toCopy);
-
-            capacityRemaining -= toCopy;
-        }
-
-        if (trailingLength > 0) {
-            if (capacityRemaining > 0 && !regionAppended) {
-                tag[tagLength++] = '_';
-                --capacityRemaining;
-            }
-
-            if (capacityRemaining > 0) {
-                /*
-                 * Copy the trailing data into the supplied buffer.  Use uprv_memmove, since we
-                 * don't know if the user-supplied buffers overlap.
-                 */
-                const int32_t toCopy =
-                    trailingLength >= capacityRemaining ? capacityRemaining : trailingLength;
-
-                uprv_memmove(
-                    &tag[tagLength],
-                    trailing,
-                    toCopy);
-            }
-        }
-
-        tagLength += trailingLength;
-
-        return u_terminateChars(
-                    tag,
-                    tagCapacity,
-                    tagLength,
-                    err);
-    }
-
-error:
-
-    /**
-     * An overflow indicates the locale ID passed in
-     * is ill-formed.  If we got here, and there was
-     * no previous error, it's an implicit overflow.
-     **/
-    if (*err ==  U_BUFFER_OVERFLOW_ERROR ||
-        U_SUCCESS(*err)) {
-        *err = U_ILLEGAL_ARGUMENT_ERROR;
-    }
-
-    return -1;
-}
-
-/**
- * Create a tag string from the supplied parameters.  The lang, script and region
- * parameters may be NULL pointers. If they are, their corresponding length parameters
- * must be less than or equal to 0.  If the lang parameter is an empty string, the
- * default value for an unknown language is written to the output buffer.
- *
- * If the length of the new string exceeds the capacity of the output buffer, 
- * the function copies as many bytes to the output buffer as it can, and returns
- * the error U_BUFFER_OVERFLOW_ERROR.
- *
- * If an illegal argument is provided, the function returns the error
- * U_ILLEGAL_ARGUMENT_ERROR.
- *
- * @param lang The language tag to use.
- * @param langLength The length of the language tag.
- * @param script The script tag to use.
- * @param scriptLength The length of the script tag.
- * @param region The region tag to use.
- * @param regionLength The length of the region tag.
- * @param trailing Any trailing data to append to the new tag.
- * @param trailingLength The length of the trailing data.
- * @param tag The output buffer.
- * @param tagCapacity The capacity of the output buffer.
- * @param err A pointer to a UErrorCode for error reporting.
- * @return The length of the tag string, which may be greater than tagCapacity.
- **/
-static int32_t U_CALLCONV
-createTagString(
-    const char* lang,
-    int32_t langLength,
-    const char* script,
-    int32_t scriptLength,
-    const char* region,
-    int32_t regionLength,
-    const char* trailing,
-    int32_t trailingLength,
-    char* tag,
-    int32_t tagCapacity,
-    UErrorCode* err)
-{
-    return createTagStringWithAlternates(
-                lang,
-                langLength,
-                script,
-                scriptLength,
-                region,
-                regionLength,
-                trailing,
-                trailingLength,
-                NULL,
-                tag,
-                tagCapacity,
-                err);
-}
-
-/**
- * Parse the language, script, and region subtags from a tag string, and copy the
- * results into the corresponding output parameters. The buffers are null-terminated,
- * unless overflow occurs.
- *
- * The langLength, scriptLength, and regionLength parameters are input/output
- * parameters, and must contain the capacity of their corresponding buffers on
- * input.  On output, they will contain the actual length of the buffers, not
- * including the null terminator.
- *
- * If the length of any of the output subtags exceeds the capacity of the corresponding
- * buffer, the function copies as many bytes to the output buffer as it can, and returns
- * the error U_BUFFER_OVERFLOW_ERROR.  It will not parse any more subtags once overflow
- * occurs.
- *
- * If an illegal argument is provided, the function returns the error
- * U_ILLEGAL_ARGUMENT_ERROR.
- *
- * @param localeID The locale ID to parse.
- * @param lang The language tag buffer.
- * @param langLength The length of the language tag.
- * @param script The script tag buffer.
- * @param scriptLength The length of the script tag.
- * @param region The region tag buffer.
- * @param regionLength The length of the region tag.
- * @param err A pointer to a UErrorCode for error reporting.
- * @return The number of chars of the localeID parameter consumed.
- **/
-static int32_t U_CALLCONV
-parseTagString(
-    const char* localeID,
-    char* lang,
-    int32_t* langLength,
-    char* script,
-    int32_t* scriptLength,
-    char* region,
-    int32_t* regionLength,
-    UErrorCode* err)
-{
-    const char* position = localeID;
-    int32_t subtagLength = 0;
-
-    if(U_FAILURE(*err) ||
-       localeID == NULL ||
-       lang == NULL ||
-       langLength == NULL ||
-       script == NULL ||
-       scriptLength == NULL ||
-       region == NULL ||
-       regionLength == NULL) {
-        goto error;
-    }
-
-    subtagLength = _getLanguage(position, lang, *langLength, &position);
-    u_terminateChars(lang, *langLength, subtagLength, err);
-
-    /*
-     * Note that we explicit consider U_STRING_NOT_TERMINATED_WARNING
-     * to be an error, because it indicates the user-supplied tag is
-     * not well-formed.
-     */
-    if(*err != U_ZERO_ERROR) {
-        goto error;
-    }
-
-    *langLength = subtagLength;
-
-    /*
-     * If no language was present, use the value of unknownLanguage
-     * instead.  Otherwise, move past any separator.
-     */
-    if (*langLength == 0) {
-        uprv_strcpy(
-            lang,
-            unknownLanguage);
-        *langLength = uprv_strlen(lang);
-    }
-    else if (_isIDSeparator(*position)) {
-        ++position;
-    }
-
-    subtagLength = _getScript(position, script, *scriptLength, &position);
-    u_terminateChars(script, *scriptLength, subtagLength, err);
-
-    if(*err != U_ZERO_ERROR) {
-        goto error;
-    }
-
-    *scriptLength = subtagLength;
-
-    if (*scriptLength > 0) {
-        if (uprv_strnicmp(script, unknownScript, *scriptLength) == 0) {
-            /**
-             * If the script part is the "unknown" script, then don't return it.
-             **/
-            *scriptLength = 0;
-        }
-
-        /*
-         * Move past any separator.
-         */
-        if (_isIDSeparator(*position)) {
-            ++position;
-        }    
-    }
-
-    subtagLength = _getCountry(position, region, *regionLength, &position);
-    u_terminateChars(region, *regionLength, subtagLength, err);
-
-    if(*err != U_ZERO_ERROR) {
-        goto error;
-    }
-
-    *regionLength = subtagLength;
-
-    if (*regionLength > 0) {
-        if (uprv_strnicmp(region, unknownRegion, *regionLength) == 0) {
-            /**
-             * If the region part is the "unknown" region, then don't return it.
-             **/
-            *regionLength = 0;
-        }
-    }
-
-exit:
-
-    return (int32_t)(position - localeID);
-
-error:
-
-    /**
-     * If we get here, we have no explicit error, it's the result of an
-     * illegal argument.
-     **/
-    if (!U_FAILURE(*err)) {
-        *err = U_ILLEGAL_ARGUMENT_ERROR;
-    }
-
-    goto exit;
-}
-
-static int32_t U_CALLCONV
-createLikelySubtagsString(
-    const char* lang,
-    int32_t langLength,
-    const char* script,
-    int32_t scriptLength,
-    const char* region,
-    int32_t regionLength,
-    const char* variants,
-    int32_t variantsLength,
-    char* tag,
-    int32_t tagCapacity,
-    UErrorCode* err)
-{
-    /**
-     * ULOC_FULLNAME_CAPACITY will provide enough capacity
-     * that we can build a string that contains the language,
-     * script and region code without worrying about overrunning
-     * the user-supplied buffer.
-     **/
-    char tagBuffer[ULOC_FULLNAME_CAPACITY];
-    char likelySubtagsBuffer[ULOC_FULLNAME_CAPACITY];
-    int32_t tagBufferLength = 0;
-
-    if(U_FAILURE(*err)) {
-        goto error;
-    }
-
-    /**
-     * Try the language with the script and region first.
-     **/
-    if (scriptLength > 0 && regionLength > 0) {
-
-        const char* likelySubtags = NULL;
-
-        tagBufferLength = createTagString(
-            lang,
-            langLength,
-            script,
-            scriptLength,
-            region,
-            regionLength,
-            NULL,
-            0,
-            tagBuffer,
-            sizeof(tagBuffer),
-            err);
-        if(U_FAILURE(*err)) {
-            goto error;
-        }
-
-        likelySubtags =
-            findLikelySubtags(
-                tagBuffer,
-                likelySubtagsBuffer,
-                sizeof(likelySubtagsBuffer),
-                err);
-        if(U_FAILURE(*err)) {
-            goto error;
-        }
-
-        if (likelySubtags != NULL) {
-            /* Always use the language tag from the
-               maximal string, since it may be more
-               specific than the one provided. */
-            return createTagStringWithAlternates(
-                        NULL,
-                        0,
-                        NULL,
-                        0,
-                        NULL,
-                        0,
-                        variants,
-                        variantsLength,
-                        likelySubtags,
-                        tag,
-                        tagCapacity,
-                        err);
-        }
-    }
-
-    /**
-     * Try the language with just the script.
-     **/
-    if (scriptLength > 0) {
-
-        const char* likelySubtags = NULL;
-
-        tagBufferLength = createTagString(
-            lang,
-            langLength,
-            script,
-            scriptLength,
-            NULL,
-            0,
-            NULL,
-            0,
-            tagBuffer,
-            sizeof(tagBuffer),
-            err);
-        if(U_FAILURE(*err)) {
-            goto error;
-        }
-
-        likelySubtags =
-            findLikelySubtags(
-                tagBuffer,
-                likelySubtagsBuffer,
-                sizeof(likelySubtagsBuffer),
-                err);
-        if(U_FAILURE(*err)) {
-            goto error;
-        }
-
-        if (likelySubtags != NULL) {
-            /* Always use the language tag from the
-               maximal string, since it may be more
-               specific than the one provided. */
-            return createTagStringWithAlternates(
-                        NULL,
-                        0,
-                        NULL,
-                        0,
-                        region,
-                        regionLength,
-                        variants,
-                        variantsLength,
-                        likelySubtags,
-                        tag,
-                        tagCapacity,
-                        err);
-        }
-    }
-
-    /**
-     * Try the language with just the region.
-     **/
-    if (regionLength > 0) {
-
-        const char* likelySubtags = NULL;
-
-        createTagString(
-            lang,
-            langLength,
-            NULL,
-            0,
-            region,
-            regionLength,
-            NULL,
-            0,
-            tagBuffer,
-            sizeof(tagBuffer),
-            err);
-        if(U_FAILURE(*err)) {
-            goto error;
-        }
-
-        likelySubtags =
-            findLikelySubtags(
-                tagBuffer,
-                likelySubtagsBuffer,
-                sizeof(likelySubtagsBuffer),
-                err);
-        if(U_FAILURE(*err)) {
-            goto error;
-        }
-
-        if (likelySubtags != NULL) {
-            /* Always use the language tag from the
-               maximal string, since it may be more
-               specific than the one provided. */
-            return createTagStringWithAlternates(
-                        NULL,
-                        0,
-                        script,
-                        scriptLength,
-                        NULL,
-                        0,
-                        variants,
-                        variantsLength,
-                        likelySubtags,
-                        tag,
-                        tagCapacity,
-                        err);
-        }
-    }
-
-    /**
-     * Finally, try just the language.
-     **/
-    {
-        const char* likelySubtags = NULL;
-
-        createTagString(
-            lang,
-            langLength,
-            NULL,
-            0,
-            NULL,
-            0,
-            NULL,
-            0,
-            tagBuffer,
-            sizeof(tagBuffer),
-            err);
-        if(U_FAILURE(*err)) {
-            goto error;
-        }
-
-        likelySubtags =
-            findLikelySubtags(
-                tagBuffer,
-                likelySubtagsBuffer,
-                sizeof(likelySubtagsBuffer),
-                err);
-        if(U_FAILURE(*err)) {
-            goto error;
-        }
-
-        if (likelySubtags != NULL) {
-            /* Always use the language tag from the
-               maximal string, since it may be more
-               specific than the one provided. */
-            return createTagStringWithAlternates(
-                        NULL,
-                        0,
-                        script,
-                        scriptLength,
-                        region,
-                        regionLength,
-                        variants,
-                        variantsLength,
-                        likelySubtags,
-                        tag,
-                        tagCapacity,
-                        err);
-        }
-    }
-
-    return u_terminateChars(
-                tag,
-                tagCapacity,
-                0,
-                err);
-
-error:
-
-    if (!U_FAILURE(*err)) {
-        *err = U_ILLEGAL_ARGUMENT_ERROR;
-    }
-
-    return -1;
-}
-
-static int32_t
-_uloc_addLikelySubtags(const char*    localeID,
-         char* maximizedLocaleID,
-         int32_t maximizedLocaleIDCapacity,
-         UErrorCode* err)
-{
-    char lang[ULOC_LANG_CAPACITY];
-    int32_t langLength = sizeof(lang);
-    char script[ULOC_SCRIPT_CAPACITY];
-    int32_t scriptLength = sizeof(script);
-    char region[ULOC_COUNTRY_CAPACITY];
-    int32_t regionLength = sizeof(region);
-    const char* trailing = "";
-    int32_t trailingLength = 0;
-    int32_t trailingIndex = 0;
-    int32_t resultLength = 0;
-
-    if(U_FAILURE(*err)) {
-        goto error;
-    }
-    else if (localeID == NULL ||
-             maximizedLocaleID == NULL ||
-             maximizedLocaleIDCapacity <= 0) {
-        goto error;
-    }
-
-    trailingIndex = parseTagString(
-        localeID,
-        lang,
-        &langLength,
-        script,
-        &scriptLength,
-        region,
-        &regionLength,
-        err);
-    if(U_FAILURE(*err)) {
-        /* Overflow indicates an illegal argument error */
-        if (*err == U_BUFFER_OVERFLOW_ERROR) {
-            *err = U_ILLEGAL_ARGUMENT_ERROR;
-        }
-
-        goto error;
-    }
-
-    /* Find the length of the trailing portion. */
-    trailing = &localeID[trailingIndex];
-    trailingLength = uprv_strlen(trailing);
-
-    resultLength =
-        createLikelySubtagsString(
-            lang,
-            langLength,
-            script,
-            scriptLength,
-            region,
-            regionLength,
-            trailing,
-            trailingLength,
-            maximizedLocaleID,
-            maximizedLocaleIDCapacity,
-            err);
-
-    if (resultLength == 0) {
-        const int32_t localIDLength =
-            uprv_strlen(localeID);
-
-        /*
-         * If we get here, we need to return localeID.
-         */
-        uprv_memcpy(
-            maximizedLocaleID,
-            localeID,
-            localIDLength <= maximizedLocaleIDCapacity ? 
-                localIDLength : maximizedLocaleIDCapacity);
-
-        resultLength =
-            u_terminateChars(
-                maximizedLocaleID,
-                maximizedLocaleIDCapacity,
-                localIDLength,
-                err);
-    }
-
-    return resultLength;
-
-error:
-
-    if (!U_FAILURE(*err)) {
-        *err = U_ILLEGAL_ARGUMENT_ERROR;
-    }
-
-    return -1;
-}
-
-static int32_t
-_uloc_minimizeSubtags(const char*    localeID,
-         char* minimizedLocaleID,
-         int32_t minimizedLocaleIDCapacity,
-         UErrorCode* err)
-{
-    /**
-     * ULOC_FULLNAME_CAPACITY will provide enough capacity
-     * that we can build a string that contains the language,
-     * script and region code without worrying about overrunning
-     * the user-supplied buffer.
-     **/
-    char maximizedTagBuffer[ULOC_FULLNAME_CAPACITY];
-    int32_t maximizedTagBufferLength = sizeof(maximizedTagBuffer);
-
-    char lang[ULOC_LANG_CAPACITY];
-    int32_t langLength = sizeof(lang);
-    char script[ULOC_SCRIPT_CAPACITY];
-    int32_t scriptLength = sizeof(script);
-    char region[ULOC_COUNTRY_CAPACITY];
-    int32_t regionLength = sizeof(region);
-    const char* trailing = "";
-    int32_t trailingLength = 0;
-    int32_t trailingIndex = 0;
-
-    if(U_FAILURE(*err)) {
-        goto error;
-    }
-    else if (localeID == NULL ||
-             minimizedLocaleID == NULL ||
-             minimizedLocaleIDCapacity <= 0) {
-        goto error;
-    }
-
-    trailingIndex =
-        parseTagString(
-            localeID,
-            lang,
-            &langLength,
-            script,
-            &scriptLength,
-            region,
-            &regionLength,
-            err);
-    if(U_FAILURE(*err)) {
-
-        /* Overflow indicates an illegal argument error */
-        if (*err == U_BUFFER_OVERFLOW_ERROR) {
-            *err = U_ILLEGAL_ARGUMENT_ERROR;
-        }
-
-        goto error;
-    }
-
-    /* Find the spot where the variants begin, if any. */
-    trailing = &localeID[trailingIndex];
-    trailingLength = uprv_strlen(trailing);
-
-    createTagString(
-        lang,
-        langLength,
-        script,
-        scriptLength,
-        region,
-        regionLength,
-        NULL,
-        0,
-        maximizedTagBuffer,
-        maximizedTagBufferLength,
-        err);
-    if(U_FAILURE(*err)) {
-        goto error;
-    }
-
-    /**
-     * First, we need to first get the maximization
-     * from AddLikelySubtags.
-     **/
-    maximizedTagBufferLength =
-        uloc_addLikelySubtags(
-            maximizedTagBuffer,
-            maximizedTagBuffer,
-            maximizedTagBufferLength,
-            err);
-
-    if(U_FAILURE(*err)) {
-        goto error;
-    }
-
-    /**
-     * Start first with just the language.
-     **/
-    {
-        char tagBuffer[ULOC_FULLNAME_CAPACITY];
-
-        const int32_t tagBufferLength =
-            createLikelySubtagsString(
-                lang,
-                langLength,
-                NULL,
-                0,
-                NULL,
-                0,
-                NULL,
-                0,
-                tagBuffer,
-                sizeof(tagBuffer),
-                err);
-
-        if(U_FAILURE(*err)) {
-            goto error;
-        }
-        else if (uprv_strnicmp(
-                    maximizedTagBuffer,
-                    tagBuffer,
-                    tagBufferLength) == 0) {
-
-            return createTagString(
-                        lang,
-                        langLength,
-                        NULL,
-                        0,
-                        NULL,
-                        0,
-                        trailing,
-                        trailingLength,
-                        minimizedLocaleID,
-                        minimizedLocaleIDCapacity,
-                        err);
-        }
-    }
-
-    /**
-     * Next, try the language and region.
-     **/
-    if (regionLength > 0) {
-
-        char tagBuffer[ULOC_FULLNAME_CAPACITY];
-
-        const int32_t tagBufferLength =
-            createLikelySubtagsString(
-                lang,
-                langLength,
-                NULL,
-                0,
-                region,
-                regionLength,
-                NULL,
-                0,
-                tagBuffer,
-                sizeof(tagBuffer),
-                err);
-
-        if(U_FAILURE(*err)) {
-            goto error;
-        }
-        else if (uprv_strnicmp(
-                    maximizedTagBuffer,
-                    tagBuffer,
-                    tagBufferLength) == 0) {
-
-            return createTagString(
-                        lang,
-                        langLength,
-                        NULL,
-                        0,
-                        region,
-                        regionLength,
-                        trailing,
-                        trailingLength,
-                        minimizedLocaleID,
-                        minimizedLocaleIDCapacity,
-                        err);
-        }
-    }
-
-    /**
-     * Finally, try the language and script.  This is our last chance,
-     * since trying with all three subtags would only yield the
-     * maximal version that we already have.
-     **/
-    if (scriptLength > 0 && regionLength > 0) {
-        char tagBuffer[ULOC_FULLNAME_CAPACITY];
-
-        const int32_t tagBufferLength =
-            createLikelySubtagsString(
-                lang,
-                langLength,
-                script,
-                scriptLength,
-                NULL,
-                0,
-                NULL,
-                0,
-                tagBuffer,
-                sizeof(tagBuffer),
-                err);
-
-        if(U_FAILURE(*err)) {
-            goto error;
-        }
-        else if (uprv_strnicmp(
-                    maximizedTagBuffer,
-                    tagBuffer,
-                    tagBufferLength) == 0) {
-
-            return createTagString(
-                        lang,
-                        langLength,
-                        script,
-                        scriptLength,
-                        NULL,
-                        0,
-                        trailing,
-                        trailingLength,
-                        minimizedLocaleID,
-                        minimizedLocaleIDCapacity,
-                        err);
-        }
-    }
-
-    {
-        /**
-         * If we got here, return the locale ID parameter.
-         **/
-        const int32_t localeIDLength = uprv_strlen(localeID);
-
-        uprv_memcpy(
-            minimizedLocaleID,
-            localeID,
-            localeIDLength <= minimizedLocaleIDCapacity ? 
-                localeIDLength : minimizedLocaleIDCapacity);
-
-        return u_terminateChars(
-                    minimizedLocaleID,
-                    minimizedLocaleIDCapacity,
-                    localeIDLength,
-                    err);
-    }
-
-error:
-
-    if (!U_FAILURE(*err)) {
-        *err = U_ILLEGAL_ARGUMENT_ERROR;
-    }
-
-    return -1;
-
-
-}
-
-static UBool
-do_canonicalize(const char*    localeID,
-         char* buffer,
-         int32_t bufferCapacity,
-         UErrorCode* err)
-{
-    uloc_canonicalize(
-        localeID,
-        buffer,
-        bufferCapacity,
-        err);
-
-    if (*err == U_STRING_NOT_TERMINATED_WARNING ||
-        *err == U_BUFFER_OVERFLOW_ERROR) {
-        *err = U_ILLEGAL_ARGUMENT_ERROR;
-
-        return FALSE;
-    }
-    else if (U_FAILURE(*err)) {
-
-        return FALSE;
-    }
-    else {
-        return TRUE;
-    }
-}
-
-U_DRAFT int32_t U_EXPORT2
-uloc_addLikelySubtags(const char*    localeID,
-         char* maximizedLocaleID,
-         int32_t maximizedLocaleIDCapacity,
-         UErrorCode* err)
-{
-    char localeBuffer[ULOC_FULLNAME_CAPACITY];
-
-    if (!do_canonicalize(
-        localeID,
-        localeBuffer,
-        sizeof(localeBuffer),
-        err)) {
-        return -1;
-    }
-    else {
-        return _uloc_addLikelySubtags(
-                    localeBuffer,
-                    maximizedLocaleID,
-                    maximizedLocaleIDCapacity,
-                    err);
-    }    
-}
-
-U_DRAFT int32_t U_EXPORT2
-uloc_minimizeSubtags(const char*    localeID,
-         char* minimizedLocaleID,
-         int32_t minimizedLocaleIDCapacity,
-         UErrorCode* err)
-{
-    char localeBuffer[ULOC_FULLNAME_CAPACITY];
-
-    if (!do_canonicalize(
-        localeID,
-        localeBuffer,
-        sizeof(localeBuffer),
-        err)) {
-        return -1;
-    }
-    else {
-        return _uloc_minimizeSubtags(
-                    localeBuffer,
-                    minimizedLocaleID,
-                    minimizedLocaleIDCapacity,
-                    err);
-    }    
-}
-
 /*eof*/