intl/icu/source/common/listformatter.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) 2013, International Business Machines
     5 *   Corporation and others.  All Rights Reserved.
     6 *
     7 *******************************************************************************
     8 *   file name:  listformatter.cpp
     9 *   encoding:   US-ASCII
    10 *   tab size:   8 (not used)
    11 *   indentation:4
    12 *
    13 *   created on: 2012aug27
    14 *   created by: Umesh P. Nair
    15 */
    17 #include "unicode/listformatter.h"
    18 #include "mutex.h"
    19 #include "hash.h"
    20 #include "cstring.h"
    21 #include "ulocimp.h"
    22 #include "charstr.h"
    23 #include "ucln_cmn.h"
    24 #include "uresimp.h"
    26 U_NAMESPACE_BEGIN
    28 static Hashtable* listPatternHash = NULL;
    29 static UMutex listFormatterMutex = U_MUTEX_INITIALIZER;
    30 static UChar FIRST_PARAMETER[] = { 0x7b, 0x30, 0x7d };  // "{0}"
    31 static UChar SECOND_PARAMETER[] = { 0x7b, 0x31, 0x7d };  // "{0}"
    32 static const char *STANDARD_STYLE = "standard";
    34 U_CDECL_BEGIN
    35 static UBool U_CALLCONV uprv_listformatter_cleanup() {
    36     delete listPatternHash;
    37     listPatternHash = NULL;
    38     return TRUE;
    39 }
    41 static void U_CALLCONV
    42 uprv_deleteListFormatData(void *obj) {
    43     delete static_cast<ListFormatData *>(obj);
    44 }
    46 U_CDECL_END
    48 static ListFormatData* loadListFormatData(const Locale& locale, const char* style, UErrorCode& errorCode);
    49 static void getStringByKey(const UResourceBundle* rb, const char* key, UnicodeString& result, UErrorCode& errorCode);
    51 ListFormatter::ListFormatter(const ListFormatter& other) : data(other.data) {
    52 }
    54 ListFormatter& ListFormatter::operator=(const ListFormatter& other) {
    55     data = other.data;
    56     return *this;
    57 }
    59 void ListFormatter::initializeHash(UErrorCode& errorCode) {
    60     if (U_FAILURE(errorCode)) {
    61         return;
    62     }
    64     listPatternHash = new Hashtable();
    65     if (listPatternHash == NULL) {
    66         errorCode = U_MEMORY_ALLOCATION_ERROR;
    67         return;
    68     }
    70     listPatternHash->setValueDeleter(uprv_deleteListFormatData);
    71     ucln_common_registerCleanup(UCLN_COMMON_LIST_FORMATTER, uprv_listformatter_cleanup);
    73 }
    75 const ListFormatData* ListFormatter::getListFormatData(
    76         const Locale& locale, const char *style, UErrorCode& errorCode) {
    77     if (U_FAILURE(errorCode)) {
    78         return NULL;
    79     }
    80     CharString keyBuffer(locale.getName(), errorCode);
    81     keyBuffer.append(':', errorCode).append(style, errorCode);
    82     UnicodeString key(keyBuffer.data(), -1, US_INV);
    83     ListFormatData* result = NULL;
    84     {
    85         Mutex m(&listFormatterMutex);
    86         if (listPatternHash == NULL) {
    87             initializeHash(errorCode);
    88             if (U_FAILURE(errorCode)) {
    89                 return NULL;
    90             }
    91         }
    92         result = static_cast<ListFormatData*>(listPatternHash->get(key));
    93     }
    94     if (result != NULL) {
    95         return result;
    96     }
    97     result = loadListFormatData(locale, style, errorCode);
    98     if (U_FAILURE(errorCode)) {
    99         return NULL;
   100     }
   102     {
   103         Mutex m(&listFormatterMutex);
   104         ListFormatData* temp = static_cast<ListFormatData*>(listPatternHash->get(key));
   105         if (temp != NULL) {
   106             delete result;
   107             result = temp;
   108         } else {
   109             listPatternHash->put(key, result, errorCode);
   110             if (U_FAILURE(errorCode)) {
   111                 return NULL;
   112             }
   113         }
   114     }
   115     return result;
   116 }
   118 static ListFormatData* loadListFormatData(
   119         const Locale& locale, const char * style, UErrorCode& errorCode) {
   120     UResourceBundle* rb = ures_open(NULL, locale.getName(), &errorCode);
   121     if (U_FAILURE(errorCode)) {
   122         ures_close(rb);
   123         return NULL;
   124     }
   125     rb = ures_getByKeyWithFallback(rb, "listPattern", rb, &errorCode);
   126     rb = ures_getByKeyWithFallback(rb, style, rb, &errorCode);
   128     // TODO(Travis Keep): This is a hack until fallbacks can be added for
   129     // listPattern/duration and listPattern/duration-narrow in CLDR.
   130     if (errorCode == U_MISSING_RESOURCE_ERROR) {
   131         errorCode = U_ZERO_ERROR;
   132         rb = ures_getByKeyWithFallback(rb, "standard", rb, &errorCode);
   133     }
   134     if (U_FAILURE(errorCode)) {
   135         ures_close(rb);
   136         return NULL;
   137     }
   138     UnicodeString two, start, middle, end;
   139     getStringByKey(rb, "2", two, errorCode);
   140     getStringByKey(rb, "start", start, errorCode);
   141     getStringByKey(rb, "middle", middle, errorCode);
   142     getStringByKey(rb, "end", end, errorCode);
   143     ures_close(rb);
   144     if (U_FAILURE(errorCode)) {
   145         return NULL;
   146     }
   147     ListFormatData* result = new ListFormatData(two, start, middle, end);
   148     if (result == NULL) {
   149         errorCode = U_MEMORY_ALLOCATION_ERROR;
   150         return NULL;
   151     }
   152     return result;
   153 }
   155 static void getStringByKey(const UResourceBundle* rb, const char* key, UnicodeString& result, UErrorCode& errorCode) {
   156     int32_t len;
   157     const UChar* ustr = ures_getStringByKeyWithFallback(rb, key, &len, &errorCode);
   158     if (U_FAILURE(errorCode)) {
   159       return;
   160     }
   161     result.setTo(ustr, len);
   162 }
   164 ListFormatter* ListFormatter::createInstance(UErrorCode& errorCode) {
   165     Locale locale;  // The default locale.
   166     return createInstance(locale, errorCode);
   167 }
   169 ListFormatter* ListFormatter::createInstance(const Locale& locale, UErrorCode& errorCode) {
   170     return createInstance(locale, STANDARD_STYLE, errorCode);
   171 }
   173 ListFormatter* ListFormatter::createInstance(const Locale& locale, const char *style, UErrorCode& errorCode) {
   174     Locale tempLocale = locale;
   175     const ListFormatData* listFormatData = getListFormatData(tempLocale, style, errorCode);
   176     if (U_FAILURE(errorCode)) {
   177         return NULL;
   178     }
   179     ListFormatter* p = new ListFormatter(listFormatData);
   180     if (p == NULL) {
   181         errorCode = U_MEMORY_ALLOCATION_ERROR;
   182         return NULL;
   183     }
   184     return p;
   185 }
   188 ListFormatter::ListFormatter(const ListFormatData* listFormatterData) : data(listFormatterData) {
   189 }
   191 ListFormatter::~ListFormatter() {}
   193 UnicodeString& ListFormatter::format(const UnicodeString items[], int32_t nItems,
   194                       UnicodeString& appendTo, UErrorCode& errorCode) const {
   195     if (U_FAILURE(errorCode)) {
   196         return appendTo;
   197     }
   198     if (data == NULL) {
   199         errorCode = U_INVALID_STATE_ERROR;
   200         return appendTo;
   201     }
   203     if (nItems > 0) {
   204         UnicodeString newString = items[0];
   205         if (nItems == 2) {
   206             addNewString(data->twoPattern, newString, items[1], errorCode);
   207         } else if (nItems > 2) {
   208             addNewString(data->startPattern, newString, items[1], errorCode);
   209             int32_t i;
   210             for (i = 2; i < nItems - 1; ++i) {
   211                 addNewString(data->middlePattern, newString, items[i], errorCode);
   212             }
   213             addNewString(data->endPattern, newString, items[nItems - 1], errorCode);
   214         }
   215         if (U_SUCCESS(errorCode)) {
   216             appendTo += newString;
   217         }
   218     }
   219     return appendTo;
   220 }
   222 /**
   223  * Joins originalString and nextString using the pattern pat and puts the result in
   224  * originalString.
   225  */
   226 void ListFormatter::addNewString(const UnicodeString& pat, UnicodeString& originalString,
   227                                  const UnicodeString& nextString, UErrorCode& errorCode) const {
   228     if (U_FAILURE(errorCode)) {
   229         return;
   230     }
   232     int32_t p0Offset = pat.indexOf(FIRST_PARAMETER, 3, 0);
   233     if (p0Offset < 0) {
   234         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
   235         return;
   236     }
   237     int32_t p1Offset = pat.indexOf(SECOND_PARAMETER, 3, 0);
   238     if (p1Offset < 0) {
   239         errorCode = U_ILLEGAL_ARGUMENT_ERROR;
   240         return;
   241     }
   243     int32_t i, j;
   245     const UnicodeString* firstString;
   246     const UnicodeString* secondString;
   247     if (p0Offset < p1Offset) {
   248         i = p0Offset;
   249         j = p1Offset;
   250         firstString = &originalString;
   251         secondString = &nextString;
   252     } else {
   253         i = p1Offset;
   254         j = p0Offset;
   255         firstString = &nextString;
   256         secondString = &originalString;
   257     }
   259     UnicodeString result = UnicodeString(pat, 0, i) + *firstString;
   260     result += UnicodeString(pat, i+3, j-i-3);
   261     result += *secondString;
   262     result += UnicodeString(pat, j+3);
   263     originalString = result;
   264 }
   266 U_NAMESPACE_END

mercurial