intl/icu/source/common/locdispnames.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /*
     2 *******************************************************************************
     3 *
     4 *   Copyright (C) 1997-2013, International Business Machines
     5 *   Corporation and others.  All Rights Reserved.
     6 *
     7 *******************************************************************************
     8 *   file name:  locdispnames.cpp
     9 *   encoding:   US-ASCII
    10 *   tab size:   8 (not used)
    11 *   indentation:4
    12 *
    13 *   created on: 2010feb25
    14 *   created by: Markus W. Scherer
    15 *
    16 *   Code for locale display names, separated out from other .cpp files
    17 *   that then do not depend on resource bundle code and display name data.
    18 */
    20 #include "unicode/utypes.h"
    21 #include "unicode/brkiter.h"
    22 #include "unicode/locid.h"
    23 #include "unicode/uloc.h"
    24 #include "unicode/ures.h"
    25 #include "unicode/ustring.h"
    26 #include "cmemory.h"
    27 #include "cstring.h"
    28 #include "putilimp.h"
    29 #include "ulocimp.h"
    30 #include "uresimp.h"
    31 #include "ureslocs.h"
    32 #include "ustr_imp.h"
    34 // C++ API ----------------------------------------------------------------- ***
    36 U_NAMESPACE_BEGIN
    38 UnicodeString&
    39 Locale::getDisplayLanguage(UnicodeString& dispLang) const
    40 {
    41     return this->getDisplayLanguage(getDefault(), dispLang);
    42 }
    44 /*We cannot make any assumptions on the size of the output display strings
    45 * Yet, since we are calling through to a C API, we need to set limits on
    46 * buffer size. For all the following getDisplay functions we first attempt
    47 * to fill up a stack allocated buffer. If it is to small we heap allocated
    48 * the exact buffer we need copy it to the UnicodeString and delete it*/
    50 UnicodeString&
    51 Locale::getDisplayLanguage(const Locale &displayLocale,
    52                            UnicodeString &result) const {
    53     UChar *buffer;
    54     UErrorCode errorCode=U_ZERO_ERROR;
    55     int32_t length;
    57     buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
    58     if(buffer==0) {
    59         result.truncate(0);
    60         return result;
    61     }
    63     length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
    64                                    buffer, result.getCapacity(),
    65                                    &errorCode);
    66     result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
    68     if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
    69         buffer=result.getBuffer(length);
    70         if(buffer==0) {
    71             result.truncate(0);
    72             return result;
    73         }
    74         errorCode=U_ZERO_ERROR;
    75         length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
    76                                        buffer, result.getCapacity(),
    77                                        &errorCode);
    78         result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
    79     }
    81     return result;
    82 }
    84 UnicodeString&
    85 Locale::getDisplayScript(UnicodeString& dispScript) const
    86 {
    87     return this->getDisplayScript(getDefault(), dispScript);
    88 }
    90 UnicodeString&
    91 Locale::getDisplayScript(const Locale &displayLocale,
    92                           UnicodeString &result) const {
    93     UChar *buffer;
    94     UErrorCode errorCode=U_ZERO_ERROR;
    95     int32_t length;
    97     buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
    98     if(buffer==0) {
    99         result.truncate(0);
   100         return result;
   101     }
   103     length=uloc_getDisplayScript(fullName, displayLocale.fullName,
   104                                   buffer, result.getCapacity(),
   105                                   &errorCode);
   106     result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
   108     if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
   109         buffer=result.getBuffer(length);
   110         if(buffer==0) {
   111             result.truncate(0);
   112             return result;
   113         }
   114         errorCode=U_ZERO_ERROR;
   115         length=uloc_getDisplayScript(fullName, displayLocale.fullName,
   116                                       buffer, result.getCapacity(),
   117                                       &errorCode);
   118         result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
   119     }
   121     return result;
   122 }
   124 UnicodeString&
   125 Locale::getDisplayCountry(UnicodeString& dispCntry) const
   126 {
   127     return this->getDisplayCountry(getDefault(), dispCntry);
   128 }
   130 UnicodeString&
   131 Locale::getDisplayCountry(const Locale &displayLocale,
   132                           UnicodeString &result) const {
   133     UChar *buffer;
   134     UErrorCode errorCode=U_ZERO_ERROR;
   135     int32_t length;
   137     buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
   138     if(buffer==0) {
   139         result.truncate(0);
   140         return result;
   141     }
   143     length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
   144                                   buffer, result.getCapacity(),
   145                                   &errorCode);
   146     result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
   148     if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
   149         buffer=result.getBuffer(length);
   150         if(buffer==0) {
   151             result.truncate(0);
   152             return result;
   153         }
   154         errorCode=U_ZERO_ERROR;
   155         length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
   156                                       buffer, result.getCapacity(),
   157                                       &errorCode);
   158         result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
   159     }
   161     return result;
   162 }
   164 UnicodeString&
   165 Locale::getDisplayVariant(UnicodeString& dispVar) const
   166 {
   167     return this->getDisplayVariant(getDefault(), dispVar);
   168 }
   170 UnicodeString&
   171 Locale::getDisplayVariant(const Locale &displayLocale,
   172                           UnicodeString &result) const {
   173     UChar *buffer;
   174     UErrorCode errorCode=U_ZERO_ERROR;
   175     int32_t length;
   177     buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
   178     if(buffer==0) {
   179         result.truncate(0);
   180         return result;
   181     }
   183     length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
   184                                   buffer, result.getCapacity(),
   185                                   &errorCode);
   186     result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
   188     if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
   189         buffer=result.getBuffer(length);
   190         if(buffer==0) {
   191             result.truncate(0);
   192             return result;
   193         }
   194         errorCode=U_ZERO_ERROR;
   195         length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
   196                                       buffer, result.getCapacity(),
   197                                       &errorCode);
   198         result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
   199     }
   201     return result;
   202 }
   204 UnicodeString&
   205 Locale::getDisplayName( UnicodeString& name ) const
   206 {
   207     return this->getDisplayName(getDefault(), name);
   208 }
   210 UnicodeString&
   211 Locale::getDisplayName(const Locale &displayLocale,
   212                        UnicodeString &result) const {
   213     UChar *buffer;
   214     UErrorCode errorCode=U_ZERO_ERROR;
   215     int32_t length;
   217     buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
   218     if(buffer==0) {
   219         result.truncate(0);
   220         return result;
   221     }
   223     length=uloc_getDisplayName(fullName, displayLocale.fullName,
   224                                buffer, result.getCapacity(),
   225                                &errorCode);
   226     result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
   228     if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
   229         buffer=result.getBuffer(length);
   230         if(buffer==0) {
   231             result.truncate(0);
   232             return result;
   233         }
   234         errorCode=U_ZERO_ERROR;
   235         length=uloc_getDisplayName(fullName, displayLocale.fullName,
   236                                    buffer, result.getCapacity(),
   237                                    &errorCode);
   238         result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
   239     }
   241     return result;
   242 }
   244 #if ! UCONFIG_NO_BREAK_ITERATION
   246 // -------------------------------------
   247 // Gets the objectLocale display name in the default locale language.
   248 UnicodeString& U_EXPORT2
   249 BreakIterator::getDisplayName(const Locale& objectLocale,
   250                              UnicodeString& name)
   251 {
   252     return objectLocale.getDisplayName(name);
   253 }
   255 // -------------------------------------
   256 // Gets the objectLocale display name in the displayLocale language.
   257 UnicodeString& U_EXPORT2
   258 BreakIterator::getDisplayName(const Locale& objectLocale,
   259                              const Locale& displayLocale,
   260                              UnicodeString& name)
   261 {
   262     return objectLocale.getDisplayName(displayLocale, name);
   263 }
   265 #endif
   268 U_NAMESPACE_END
   270 // C API ------------------------------------------------------------------- ***
   272 U_NAMESPACE_USE
   274 /* ### Constants **************************************************/
   276 /* These strings describe the resources we attempt to load from
   277  the locale ResourceBundle data file.*/
   278 static const char _kLanguages[]       = "Languages";
   279 static const char _kScripts[]         = "Scripts";
   280 static const char _kScriptsStandAlone[] = "Scripts%stand-alone";
   281 static const char _kCountries[]       = "Countries";
   282 static const char _kVariants[]        = "Variants";
   283 static const char _kKeys[]            = "Keys";
   284 static const char _kTypes[]           = "Types";
   285 //static const char _kRootName[]        = "root";
   286 static const char _kCurrency[]        = "currency";
   287 static const char _kCurrencies[]      = "Currencies";
   288 static const char _kLocaleDisplayPattern[] = "localeDisplayPattern";
   289 static const char _kPattern[]         = "pattern";
   290 static const char _kSeparator[]       = "separator";
   292 /* ### Display name **************************************************/
   294 static int32_t
   295 _getStringOrCopyKey(const char *path, const char *locale,
   296                     const char *tableKey, 
   297                     const char* subTableKey,
   298                     const char *itemKey,
   299                     const char *substitute,
   300                     UChar *dest, int32_t destCapacity,
   301                     UErrorCode *pErrorCode) {
   302     const UChar *s = NULL;
   303     int32_t length = 0;
   305     if(itemKey==NULL) {
   306         /* top-level item: normal resource bundle access */
   307         UResourceBundle *rb;
   309         rb=ures_open(path, locale, pErrorCode);
   311         if(U_SUCCESS(*pErrorCode)) {
   312             s=ures_getStringByKey(rb, tableKey, &length, pErrorCode);
   313             /* see comment about closing rb near "return item;" in _res_getTableStringWithFallback() */
   314             ures_close(rb);
   315         }
   316     } else {
   317         /* Language code should not be a number. If it is, set the error code. */
   318         if (!uprv_strncmp(tableKey, "Languages", 9) && uprv_strtol(itemKey, NULL, 10)) {
   319             *pErrorCode = U_MISSING_RESOURCE_ERROR;
   320         } else {
   321             /* second-level item, use special fallback */
   322             s=uloc_getTableStringWithFallback(path, locale,
   323                                                tableKey, 
   324                                                subTableKey,
   325                                                itemKey,
   326                                                &length,
   327                                                pErrorCode);
   328         }
   329     }
   331     if(U_SUCCESS(*pErrorCode)) {
   332         int32_t copyLength=uprv_min(length, destCapacity);
   333         if(copyLength>0 && s != NULL) {
   334             u_memcpy(dest, s, copyLength);
   335         }
   336     } else {
   337         /* no string from a resource bundle: convert the substitute */
   338         length=(int32_t)uprv_strlen(substitute);
   339         u_charsToUChars(substitute, dest, uprv_min(length, destCapacity));
   340         *pErrorCode=U_USING_DEFAULT_WARNING;
   341     }
   343     return u_terminateUChars(dest, destCapacity, length, pErrorCode);
   344 }
   346 typedef  int32_t U_CALLCONV UDisplayNameGetter(const char *, char *, int32_t, UErrorCode *);
   348 static int32_t
   349 _getDisplayNameForComponent(const char *locale,
   350                             const char *displayLocale,
   351                             UChar *dest, int32_t destCapacity,
   352                             UDisplayNameGetter *getter,
   353                             const char *tag,
   354                             UErrorCode *pErrorCode) {
   355     char localeBuffer[ULOC_FULLNAME_CAPACITY*4];
   356     int32_t length;
   357     UErrorCode localStatus;
   358     const char* root = NULL;
   360     /* argument checking */
   361     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
   362         return 0;
   363     }
   365     if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
   366         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
   367         return 0;
   368     }
   370     localStatus = U_ZERO_ERROR;
   371     length=(*getter)(locale, localeBuffer, sizeof(localeBuffer), &localStatus);
   372     if(U_FAILURE(localStatus) || localStatus==U_STRING_NOT_TERMINATED_WARNING) {
   373         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
   374         return 0;
   375     }
   376     if(length==0) {
   377         return u_terminateUChars(dest, destCapacity, 0, pErrorCode);
   378     }
   380     root = tag == _kCountries ? U_ICUDATA_REGION : U_ICUDATA_LANG;
   382     return _getStringOrCopyKey(root, displayLocale,
   383                                tag, NULL, localeBuffer,
   384                                localeBuffer,
   385                                dest, destCapacity,
   386                                pErrorCode);
   387 }
   389 U_CAPI int32_t U_EXPORT2
   390 uloc_getDisplayLanguage(const char *locale,
   391                         const char *displayLocale,
   392                         UChar *dest, int32_t destCapacity,
   393                         UErrorCode *pErrorCode) {
   394     return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
   395                 uloc_getLanguage, _kLanguages, pErrorCode);
   396 }
   398 U_CAPI int32_t U_EXPORT2
   399 uloc_getDisplayScript(const char* locale,
   400                       const char* displayLocale,
   401                       UChar *dest, int32_t destCapacity,
   402                       UErrorCode *pErrorCode)
   403 {
   404 	UErrorCode err = U_ZERO_ERROR;
   405 	int32_t res = _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
   406                 uloc_getScript, _kScriptsStandAlone, &err);
   408 	if ( err == U_USING_DEFAULT_WARNING ) {
   409         return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
   410                     uloc_getScript, _kScripts, pErrorCode);
   411 	} else {
   412 		*pErrorCode = err;
   413 		return res;
   414 	}
   415 }
   417 U_INTERNAL int32_t U_EXPORT2
   418 uloc_getDisplayScriptInContext(const char* locale,
   419                       const char* displayLocale,
   420                       UChar *dest, int32_t destCapacity,
   421                       UErrorCode *pErrorCode)
   422 {
   423     return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
   424                     uloc_getScript, _kScripts, pErrorCode);
   425 }
   427 U_CAPI int32_t U_EXPORT2
   428 uloc_getDisplayCountry(const char *locale,
   429                        const char *displayLocale,
   430                        UChar *dest, int32_t destCapacity,
   431                        UErrorCode *pErrorCode) {
   432     return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
   433                 uloc_getCountry, _kCountries, pErrorCode);
   434 }
   436 /*
   437  * TODO separate variant1_variant2_variant3...
   438  * by getting each tag's display string and concatenating them with ", "
   439  * in between - similar to uloc_getDisplayName()
   440  */
   441 U_CAPI int32_t U_EXPORT2
   442 uloc_getDisplayVariant(const char *locale,
   443                        const char *displayLocale,
   444                        UChar *dest, int32_t destCapacity,
   445                        UErrorCode *pErrorCode) {
   446     return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
   447                 uloc_getVariant, _kVariants, pErrorCode);
   448 }
   450 /* Instead of having a separate pass for 'special' patterns, reintegrate the two
   451  * so we don't get bitten by preflight bugs again.  We can be reasonably efficient
   452  * without two separate code paths, this code isn't that performance-critical.
   453  *
   454  * This code is general enough to deal with patterns that have a prefix or swap the
   455  * language and remainder components, since we gave developers enough rope to do such
   456  * things if they futz with the pattern data.  But since we don't give them a way to
   457  * specify a pattern for arbitrary combinations of components, there's not much use in
   458  * that.  I don't think our data includes such patterns, the only variable I know if is
   459  * whether there is a space before the open paren, or not.  Oh, and zh uses different
   460  * chars than the standard open/close paren (which ja and ko use, btw).
   461  */
   462 U_CAPI int32_t U_EXPORT2
   463 uloc_getDisplayName(const char *locale,
   464                     const char *displayLocale,
   465                     UChar *dest, int32_t destCapacity,
   466                     UErrorCode *pErrorCode)
   467 {
   468     static const UChar defaultSeparator[9] = { 0x007b, 0x0030, 0x007d, 0x002c, 0x0020, 0x007b, 0x0031, 0x007d, 0x0000 }; /* "{0}, {1}" */
   469     static const UChar sub0[4] = { 0x007b, 0x0030, 0x007d , 0x0000 } ; /* {0} */
   470     static const UChar sub1[4] = { 0x007b, 0x0031, 0x007d , 0x0000 } ; /* {1} */
   471     static const int32_t subLen = 3;
   472     static const UChar defaultPattern[10] = {
   473         0x007b, 0x0030, 0x007d, 0x0020, 0x0028, 0x007b, 0x0031, 0x007d, 0x0029, 0x0000
   474     }; /* {0} ({1}) */
   475     static const int32_t defaultPatLen = 9;
   476     static const int32_t defaultSub0Pos = 0;
   477     static const int32_t defaultSub1Pos = 5;
   479     int32_t length; /* of formatted result */
   481     const UChar *separator;
   482     int32_t sepLen = 0;
   483     const UChar *pattern;
   484     int32_t patLen = 0;
   485     int32_t sub0Pos, sub1Pos;
   487     UChar formatOpenParen         = 0x0028; // (
   488     UChar formatReplaceOpenParen  = 0x005B; // [
   489     UChar formatCloseParen        = 0x0029; // )
   490     UChar formatReplaceCloseParen = 0x005D; // ]
   492     UBool haveLang = TRUE; /* assume true, set false if we find we don't have
   493                               a lang component in the locale */
   494     UBool haveRest = TRUE; /* assume true, set false if we find we don't have
   495                               any other component in the locale */
   496     UBool retry = FALSE; /* set true if we need to retry, see below */
   498     int32_t langi = 0; /* index of the language substitution (0 or 1), virtually always 0 */
   500     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
   501         return 0;
   502     }
   504     if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
   505         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
   506         return 0;
   507     }
   509     {
   510         UErrorCode status = U_ZERO_ERROR;
   511         UResourceBundle* locbundle=ures_open(U_ICUDATA_LANG, displayLocale, &status);
   512         UResourceBundle* dspbundle=ures_getByKeyWithFallback(locbundle, _kLocaleDisplayPattern,
   513                                                              NULL, &status);
   515         separator=ures_getStringByKeyWithFallback(dspbundle, _kSeparator, &sepLen, &status);
   516         pattern=ures_getStringByKeyWithFallback(dspbundle, _kPattern, &patLen, &status);
   518         ures_close(dspbundle);
   519         ures_close(locbundle);
   520     }
   522     /* If we couldn't find any data, then use the defaults */
   523     if(sepLen == 0) {
   524        separator = defaultSeparator;
   525     }
   526     /* #10244: Even though separator is now a pattern, it is awkward to handle it as such
   527      * here since we are trying to build the display string in place in the dest buffer,
   528      * and to handle it as a pattern would entail having separate storage for the
   529      * substrings that need to be combined (the first of which may be the result of
   530      * previous such combinations). So for now we continue to treat the portion between
   531      * {0} and {1} as a string to be appended when joining substrings, ignoring anything
   532      * that is before {0} or after {1} (no existing separator pattern has any such thing).
   533      * This is similar to how pattern is handled below.
   534      */
   535     {
   536         UChar *p0=u_strstr(separator, sub0);
   537         UChar *p1=u_strstr(separator, sub1);
   538         if (p0==NULL || p1==NULL || p1<p0) {
   539             *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
   540             return 0;
   541         }
   542         separator = (const UChar *)p0 + subLen;
   543         sepLen = p1 - separator;
   544     }
   546     if(patLen==0 || (patLen==defaultPatLen && !u_strncmp(pattern, defaultPattern, patLen))) {
   547         pattern=defaultPattern;
   548         patLen=defaultPatLen;
   549         sub0Pos=defaultSub0Pos;
   550         sub1Pos=defaultSub1Pos;
   551         // use default formatOpenParen etc. set above
   552     } else { /* non-default pattern */
   553         UChar *p0=u_strstr(pattern, sub0);
   554         UChar *p1=u_strstr(pattern, sub1);
   555         if (p0==NULL || p1==NULL) {
   556             *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
   557             return 0;
   558         }
   559         sub0Pos=p0-pattern;
   560         sub1Pos=p1-pattern;
   561         if (sub1Pos < sub0Pos) { /* a very odd pattern */
   562             int32_t t=sub0Pos; sub0Pos=sub1Pos; sub1Pos=t;
   563             langi=1;
   564         }
   565         if (u_strchr(pattern, 0xFF08) != NULL) {
   566             formatOpenParen         = 0xFF08; // fullwidth (
   567             formatReplaceOpenParen  = 0xFF3B; // fullwidth [
   568             formatCloseParen        = 0xFF09; // fullwidth )
   569             formatReplaceCloseParen = 0xFF3D; // fullwidth ]
   570         }
   571     }
   573     /* We loop here because there is one case in which after the first pass we could need to
   574      * reextract the data.  If there's initial padding before the first element, we put in
   575      * the padding and then write that element.  If it turns out there's no second element,
   576      * we didn't need the padding.  If we do need the data (no preflight), and the first element
   577      * would have fit but for the padding, we need to reextract.  In this case (only) we
   578      * adjust the parameters so padding is not added, and repeat.
   579      */
   580     do {
   581         UChar* p=dest;
   582         int32_t patPos=0; /* position in the pattern, used for non-substitution portions */
   583         int32_t langLen=0; /* length of language substitution */
   584         int32_t langPos=0; /* position in output of language substitution */
   585         int32_t restLen=0; /* length of 'everything else' substitution */
   586         int32_t restPos=0; /* position in output of 'everything else' substitution */
   587         UEnumeration* kenum = NULL; /* keyword enumeration */
   589         /* prefix of pattern, extremely likely to be empty */
   590         if(sub0Pos) {
   591             if(destCapacity >= sub0Pos) {
   592                 while (patPos < sub0Pos) {
   593                     *p++ = pattern[patPos++];
   594                 }
   595             } else {
   596                 patPos=sub0Pos;
   597             }
   598             length=sub0Pos;
   599         } else {
   600             length=0;
   601         }
   603         for(int32_t subi=0,resti=0;subi<2;) { /* iterate through patterns 0 and 1*/
   604             UBool subdone = FALSE; /* set true when ready to move to next substitution */
   606             /* prep p and cap for calls to get display components, pin cap to 0 since
   607                they complain if cap is negative */
   608             int32_t cap=destCapacity-length;
   609             if (cap <= 0) {
   610                 cap=0;
   611             } else {
   612                 p=dest+length;
   613             }
   615             if (subi == langi) { /* {0}*/
   616                 if(haveLang) {
   617                     langPos=length;
   618                     langLen=uloc_getDisplayLanguage(locale, displayLocale, p, cap, pErrorCode);
   619                     length+=langLen;
   620                     haveLang=langLen>0;
   621                 }
   622                 subdone=TRUE;
   623             } else { /* {1} */
   624                 if(!haveRest) {
   625                     subdone=TRUE;
   626                 } else {
   627                     int32_t len; /* length of component (plus other stuff) we just fetched */
   628                     switch(resti++) {
   629                         case 0:
   630                             restPos=length;
   631                             len=uloc_getDisplayScriptInContext(locale, displayLocale, p, cap, pErrorCode);
   632                             break;
   633                         case 1:
   634                             len=uloc_getDisplayCountry(locale, displayLocale, p, cap, pErrorCode);
   635                             break;
   636                         case 2:
   637                             len=uloc_getDisplayVariant(locale, displayLocale, p, cap, pErrorCode);
   638                             break;
   639                         case 3:
   640                             kenum = uloc_openKeywords(locale, pErrorCode);
   641                             /* fall through */
   642                         default: {
   643                             const char* kw=uenum_next(kenum, &len, pErrorCode);
   644                             if (kw == NULL) {
   645                                 uenum_close(kenum);
   646                                 len=0; /* mark that we didn't add a component */
   647                                 subdone=TRUE;
   648                             } else {
   649                                 /* incorporating this behavior into the loop made it even more complex,
   650                                    so just special case it here */
   651                                 len = uloc_getDisplayKeyword(kw, displayLocale, p, cap, pErrorCode);
   652                                 if(len) {
   653                                     if(len < cap) {
   654                                         p[len]=0x3d; /* '=', assume we'll need it */
   655                                     }
   656                                     len+=1;
   658                                     /* adjust for call to get keyword */
   659                                     cap-=len;
   660                                     if(cap <= 0) {
   661                                         cap=0;
   662                                     } else {
   663                                         p+=len;
   664                                     }
   665                                 }
   666                                 /* reset for call below */
   667                                 if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) {
   668                                     *pErrorCode=U_ZERO_ERROR;
   669                                 }
   670                                 int32_t vlen = uloc_getDisplayKeywordValue(locale, kw, displayLocale,
   671                                                                            p, cap, pErrorCode);
   672                                 if(len) {
   673                                     if(vlen==0) {
   674                                         --len; /* remove unneeded '=' */
   675                                     }
   676                                     /* restore cap and p to what they were at start */
   677                                     cap=destCapacity-length;
   678                                     if(cap <= 0) {
   679                                         cap=0;
   680                                     } else {
   681                                         p=dest+length;
   682                                     }
   683                                 }
   684                                 len+=vlen; /* total we added for key + '=' + value */
   685                             }
   686                         } break;
   687                     } /* end switch */
   689                     if (len>0) {
   690                         /* we addeed a component, so add separator and write it if there's room. */
   691                         if(len+sepLen<=cap) {
   692                             const UChar * plimit = p + len;
   693                             for (; p < plimit; p++) {
   694                                 if (*p == formatOpenParen) {
   695                                     *p = formatReplaceOpenParen;
   696                                 } else if (*p == formatCloseParen) {
   697                                     *p = formatReplaceCloseParen;
   698                                 }
   699                             }
   700                             for(int32_t i=0;i<sepLen;++i) {
   701                                 *p++=separator[i];
   702                             }
   703                         }
   704                         length+=len+sepLen;
   705                     } else if(subdone) {
   706                         /* remove separator if we added it */
   707                         if (length!=restPos) {
   708                             length-=sepLen;
   709                         }
   710                         restLen=length-restPos;
   711                         haveRest=restLen>0;
   712                     }
   713                 }
   714             }
   716             if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) {
   717                 *pErrorCode=U_ZERO_ERROR;
   718             }
   720             if(subdone) {
   721                 if(haveLang && haveRest) {
   722                     /* append internal portion of pattern, the first time,
   723                        or last portion of pattern the second time */
   724                     int32_t padLen;
   725                     patPos+=subLen;
   726                     padLen=(subi==0 ? sub1Pos : patLen)-patPos;
   727                     if(length+padLen < destCapacity) {
   728                         p=dest+length;
   729                         for(int32_t i=0;i<padLen;++i) {
   730                             *p++=pattern[patPos++];
   731                         }
   732                     } else {
   733                         patPos+=padLen;
   734                     }
   735                     length+=padLen;
   736                 } else if(subi==0) {
   737                     /* don't have first component, reset for second component */
   738                     sub0Pos=0;
   739                     length=0;
   740                 } else if(length>0) {
   741                     /* true length is the length of just the component we got. */
   742                     length=haveLang?langLen:restLen;
   743                     if(dest && sub0Pos!=0) {
   744                         if (sub0Pos+length<=destCapacity) {
   745                             /* first component not at start of result,
   746                                but we have full component in buffer. */
   747                             u_memmove(dest, dest+(haveLang?langPos:restPos), length);
   748                         } else {
   749                             /* would have fit, but didn't because of pattern prefix. */
   750                             sub0Pos=0; /* stops initial padding (and a second retry,
   751                                           so we won't end up here again) */
   752                             retry=TRUE;
   753                         }
   754                     }
   755                 }
   757                 ++subi; /* move on to next substitution */
   758             }
   759         }
   760     } while(retry);
   762     return u_terminateUChars(dest, destCapacity, length, pErrorCode);
   763 }
   765 U_CAPI int32_t U_EXPORT2
   766 uloc_getDisplayKeyword(const char* keyword,
   767                        const char* displayLocale,
   768                        UChar* dest,
   769                        int32_t destCapacity,
   770                        UErrorCode* status){
   772     /* argument checking */
   773     if(status==NULL || U_FAILURE(*status)) {
   774         return 0;
   775     }
   777     if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
   778         *status=U_ILLEGAL_ARGUMENT_ERROR;
   779         return 0;
   780     }
   783     /* pass itemKey=NULL to look for a top-level item */
   784     return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
   785                                _kKeys, NULL, 
   786                                keyword, 
   787                                keyword,      
   788                                dest, destCapacity,
   789                                status);
   791 }
   794 #define UCURRENCY_DISPLAY_NAME_INDEX 1
   796 U_CAPI int32_t U_EXPORT2
   797 uloc_getDisplayKeywordValue(   const char* locale,
   798                                const char* keyword,
   799                                const char* displayLocale,
   800                                UChar* dest,
   801                                int32_t destCapacity,
   802                                UErrorCode* status){
   805     char keywordValue[ULOC_FULLNAME_CAPACITY*4];
   806     int32_t capacity = ULOC_FULLNAME_CAPACITY*4;
   807     int32_t keywordValueLen =0;
   809     /* argument checking */
   810     if(status==NULL || U_FAILURE(*status)) {
   811         return 0;
   812     }
   814     if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
   815         *status=U_ILLEGAL_ARGUMENT_ERROR;
   816         return 0;
   817     }
   819     /* get the keyword value */
   820     keywordValue[0]=0;
   821     keywordValueLen = uloc_getKeywordValue(locale, keyword, keywordValue, capacity, status);
   823     /* 
   824      * if the keyword is equal to currency .. then to get the display name 
   825      * we need to do the fallback ourselves
   826      */
   827     if(uprv_stricmp(keyword, _kCurrency)==0){
   829         int32_t dispNameLen = 0;
   830         const UChar *dispName = NULL;
   832         UResourceBundle *bundle     = ures_open(U_ICUDATA_CURR, displayLocale, status);
   833         UResourceBundle *currencies = ures_getByKey(bundle, _kCurrencies, NULL, status);
   834         UResourceBundle *currency   = ures_getByKeyWithFallback(currencies, keywordValue, NULL, status);
   836         dispName = ures_getStringByIndex(currency, UCURRENCY_DISPLAY_NAME_INDEX, &dispNameLen, status);
   838         /*close the bundles */
   839         ures_close(currency);
   840         ures_close(currencies);
   841         ures_close(bundle);
   843         if(U_FAILURE(*status)){
   844             if(*status == U_MISSING_RESOURCE_ERROR){
   845                 /* we just want to write the value over if nothing is available */
   846                 *status = U_USING_DEFAULT_WARNING;
   847             }else{
   848                 return 0;
   849             }
   850         }
   852         /* now copy the dispName over if not NULL */
   853         if(dispName != NULL){
   854             if(dispNameLen <= destCapacity){
   855                 uprv_memcpy(dest, dispName, dispNameLen * U_SIZEOF_UCHAR);
   856                 return u_terminateUChars(dest, destCapacity, dispNameLen, status);
   857             }else{
   858                 *status = U_BUFFER_OVERFLOW_ERROR;
   859                 return dispNameLen;
   860             }
   861         }else{
   862             /* we have not found the display name for the value .. just copy over */
   863             if(keywordValueLen <= destCapacity){
   864                 u_charsToUChars(keywordValue, dest, keywordValueLen);
   865                 return u_terminateUChars(dest, destCapacity, keywordValueLen, status);
   866             }else{
   867                  *status = U_BUFFER_OVERFLOW_ERROR;
   868                 return keywordValueLen;
   869             }
   870         }
   873     }else{
   875         return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
   876                                    _kTypes, keyword, 
   877                                    keywordValue,
   878                                    keywordValue,
   879                                    dest, destCapacity,
   880                                    status);
   881     }
   882 }

mercurial