LCOV - code coverage report
Current view: top level - intl/icu/source/common - listformatter.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 205 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 27 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // © 2016 and later: Unicode, Inc. and others.
       2             : // License & terms of use: http://www.unicode.org/copyright.html
       3             : /*
       4             : *******************************************************************************
       5             : *
       6             : *   Copyright (C) 2013-2016, International Business Machines
       7             : *   Corporation and others.  All Rights Reserved.
       8             : *
       9             : *******************************************************************************
      10             : *   file name:  listformatter.cpp
      11             : *   encoding:   UTF-8
      12             : *   tab size:   8 (not used)
      13             : *   indentation:4
      14             : *
      15             : *   created on: 2012aug27
      16             : *   created by: Umesh P. Nair
      17             : */
      18             : 
      19             : #include "unicode/listformatter.h"
      20             : #include "unicode/simpleformatter.h"
      21             : #include "mutex.h"
      22             : #include "hash.h"
      23             : #include "cstring.h"
      24             : #include "ulocimp.h"
      25             : #include "charstr.h"
      26             : #include "ucln_cmn.h"
      27             : #include "uresimp.h"
      28             : #include "resource.h"
      29             : 
      30             : U_NAMESPACE_BEGIN
      31             : 
      32           0 : struct ListFormatInternal : public UMemory {
      33             :     SimpleFormatter twoPattern;
      34             :     SimpleFormatter startPattern;
      35             :     SimpleFormatter middlePattern;
      36             :     SimpleFormatter endPattern;
      37             : 
      38           0 : ListFormatInternal(
      39             :         const UnicodeString& two,
      40             :         const UnicodeString& start,
      41             :         const UnicodeString& middle,
      42             :         const UnicodeString& end,
      43           0 :         UErrorCode &errorCode) :
      44             :         twoPattern(two, 2, 2, errorCode),
      45             :         startPattern(start, 2, 2, errorCode),
      46             :         middlePattern(middle, 2, 2, errorCode),
      47           0 :         endPattern(end, 2, 2, errorCode) {}
      48             : 
      49           0 : ListFormatInternal(const ListFormatData &data, UErrorCode &errorCode) :
      50             :         twoPattern(data.twoPattern, errorCode),
      51             :         startPattern(data.startPattern, errorCode),
      52             :         middlePattern(data.middlePattern, errorCode),
      53           0 :         endPattern(data.endPattern, errorCode) { }
      54             : 
      55           0 : ListFormatInternal(const ListFormatInternal &other) :
      56             :     twoPattern(other.twoPattern),
      57             :     startPattern(other.startPattern),
      58             :     middlePattern(other.middlePattern),
      59           0 :     endPattern(other.endPattern) { }
      60             : };
      61             : 
      62             : 
      63             : 
      64             : static Hashtable* listPatternHash = NULL;
      65             : static UMutex listFormatterMutex = U_MUTEX_INITIALIZER;
      66             : static const char *STANDARD_STYLE = "standard";
      67             : 
      68             : U_CDECL_BEGIN
      69           0 : static UBool U_CALLCONV uprv_listformatter_cleanup() {
      70           0 :     delete listPatternHash;
      71           0 :     listPatternHash = NULL;
      72           0 :     return TRUE;
      73             : }
      74             : 
      75             : static void U_CALLCONV
      76           0 : uprv_deleteListFormatInternal(void *obj) {
      77           0 :     delete static_cast<ListFormatInternal *>(obj);
      78           0 : }
      79             : 
      80             : U_CDECL_END
      81             : 
      82           0 : ListFormatter::ListFormatter(const ListFormatter& other) :
      83           0 :         owned(other.owned), data(other.data) {
      84           0 :     if (other.owned != NULL) {
      85           0 :         owned = new ListFormatInternal(*other.owned);
      86           0 :         data = owned;
      87             :     }
      88           0 : }
      89             : 
      90           0 : ListFormatter& ListFormatter::operator=(const ListFormatter& other) {
      91           0 :     if (this == &other) {
      92           0 :         return *this;
      93             :     }
      94           0 :     delete owned;
      95           0 :     if (other.owned) {
      96           0 :         owned = new ListFormatInternal(*other.owned);
      97           0 :         data = owned;
      98             :     } else {
      99           0 :         owned = NULL;
     100           0 :         data = other.data;
     101             :     }
     102           0 :     return *this;
     103             : }
     104             : 
     105           0 : void ListFormatter::initializeHash(UErrorCode& errorCode) {
     106           0 :     if (U_FAILURE(errorCode)) {
     107           0 :         return;
     108             :     }
     109             : 
     110           0 :     listPatternHash = new Hashtable();
     111           0 :     if (listPatternHash == NULL) {
     112           0 :         errorCode = U_MEMORY_ALLOCATION_ERROR;
     113           0 :         return;
     114             :     }
     115             : 
     116           0 :     listPatternHash->setValueDeleter(uprv_deleteListFormatInternal);
     117           0 :     ucln_common_registerCleanup(UCLN_COMMON_LIST_FORMATTER, uprv_listformatter_cleanup);
     118             : 
     119             : }
     120             : 
     121           0 : const ListFormatInternal* ListFormatter::getListFormatInternal(
     122             :         const Locale& locale, const char *style, UErrorCode& errorCode) {
     123           0 :     if (U_FAILURE(errorCode)) {
     124           0 :         return NULL;
     125             :     }
     126           0 :     CharString keyBuffer(locale.getName(), errorCode);
     127           0 :     keyBuffer.append(':', errorCode).append(style, errorCode);
     128           0 :     UnicodeString key(keyBuffer.data(), -1, US_INV);
     129           0 :     ListFormatInternal* result = NULL;
     130             :     {
     131           0 :         Mutex m(&listFormatterMutex);
     132           0 :         if (listPatternHash == NULL) {
     133           0 :             initializeHash(errorCode);
     134           0 :             if (U_FAILURE(errorCode)) {
     135           0 :                 return NULL;
     136             :             }
     137             :         }
     138           0 :         result = static_cast<ListFormatInternal*>(listPatternHash->get(key));
     139             :     }
     140           0 :     if (result != NULL) {
     141           0 :         return result;
     142             :     }
     143           0 :     result = loadListFormatInternal(locale, style, errorCode);
     144           0 :     if (U_FAILURE(errorCode)) {
     145           0 :         return NULL;
     146             :     }
     147             : 
     148             :     {
     149           0 :         Mutex m(&listFormatterMutex);
     150           0 :         ListFormatInternal* temp = static_cast<ListFormatInternal*>(listPatternHash->get(key));
     151           0 :         if (temp != NULL) {
     152           0 :             delete result;
     153           0 :             result = temp;
     154             :         } else {
     155           0 :             listPatternHash->put(key, result, errorCode);
     156           0 :             if (U_FAILURE(errorCode)) {
     157           0 :                 return NULL;
     158             :             }
     159             :         }
     160             :     }
     161           0 :     return result;
     162             : }
     163             : 
     164             : static const UChar solidus = 0x2F;
     165             : static const UChar aliasPrefix[] = { 0x6C,0x69,0x73,0x74,0x50,0x61,0x74,0x74,0x65,0x72,0x6E,0x2F }; // "listPattern/"
     166             : enum {
     167             :     kAliasPrefixLen = UPRV_LENGTHOF(aliasPrefix),
     168             :     kStyleLenMax = 24 // longest currently is 14
     169             : };
     170             : 
     171             : struct ListFormatter::ListPatternsSink : public ResourceSink {
     172             :     UnicodeString two, start, middle, end;
     173             : #if ((U_PLATFORM == U_PF_AIX) || (U_PLATFORM == U_PF_OS390)) && (U_CPLUSPLUS_VERSION < 11)
     174             :     char aliasedStyle[kStyleLenMax+1];
     175             :     ListPatternsSink() {
     176             :       uprv_memset(aliasedStyle, 0, kStyleLenMax+1);
     177             :     }
     178             : #else
     179             :     char aliasedStyle[kStyleLenMax+1] = {0};
     180             : 
     181           0 :     ListPatternsSink() {}
     182             : #endif
     183             :     virtual ~ListPatternsSink();
     184             : 
     185           0 :     void setAliasedStyle(UnicodeString alias) {
     186           0 :         int32_t startIndex = alias.indexOf(aliasPrefix, kAliasPrefixLen, 0);
     187           0 :         if (startIndex < 0) {
     188           0 :             return;
     189             :         }
     190           0 :         startIndex += kAliasPrefixLen;
     191           0 :         int32_t endIndex = alias.indexOf(solidus, startIndex);
     192           0 :         if (endIndex < 0) {
     193           0 :             endIndex = alias.length();
     194             :         }
     195           0 :         alias.extract(startIndex, endIndex-startIndex, aliasedStyle, kStyleLenMax+1, US_INV);
     196           0 :         aliasedStyle[kStyleLenMax] = 0;
     197             :     }
     198             : 
     199           0 :     void handleValueForPattern(ResourceValue &value, UnicodeString &pattern, UErrorCode &errorCode) {
     200           0 :         if (pattern.isEmpty()) {
     201           0 :             if (value.getType() == URES_ALIAS) {
     202           0 :                 if (aliasedStyle[0] == 0) {
     203           0 :                     setAliasedStyle(value.getAliasUnicodeString(errorCode));
     204             :                 }
     205             :             } else {
     206           0 :                 pattern = value.getUnicodeString(errorCode);
     207             :             }
     208             :         }
     209           0 :     }
     210             : 
     211           0 :     virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/,
     212             :             UErrorCode &errorCode) {
     213           0 :         aliasedStyle[0] = 0;
     214           0 :         if (value.getType() == URES_ALIAS) {
     215           0 :             setAliasedStyle(value.getAliasUnicodeString(errorCode));
     216           0 :             return;
     217             :         }
     218           0 :         ResourceTable listPatterns = value.getTable(errorCode);
     219           0 :         for (int i = 0; U_SUCCESS(errorCode) && listPatterns.getKeyAndValue(i, key, value); ++i) {
     220           0 :             if (uprv_strcmp(key, "2") == 0) {
     221           0 :                 handleValueForPattern(value, two, errorCode);
     222           0 :             } else if (uprv_strcmp(key, "end") == 0) {
     223           0 :                 handleValueForPattern(value, end, errorCode);
     224           0 :             } else if (uprv_strcmp(key, "middle") == 0) {
     225           0 :                 handleValueForPattern(value, middle, errorCode);
     226           0 :             } else if (uprv_strcmp(key, "start") == 0) {
     227           0 :                 handleValueForPattern(value, start, errorCode);
     228             :             }
     229             :         }
     230             :     }
     231             : };
     232             : 
     233             : // Virtual destructors must be defined out of line.
     234           0 : ListFormatter::ListPatternsSink::~ListPatternsSink() {}
     235             : 
     236           0 : ListFormatInternal* ListFormatter::loadListFormatInternal(
     237             :         const Locale& locale, const char * style, UErrorCode& errorCode) {
     238           0 :     UResourceBundle* rb = ures_open(NULL, locale.getName(), &errorCode);
     239           0 :     rb = ures_getByKeyWithFallback(rb, "listPattern", rb, &errorCode);
     240           0 :     if (U_FAILURE(errorCode)) {
     241           0 :         ures_close(rb);
     242           0 :         return NULL;
     243             :     }
     244           0 :     ListFormatter::ListPatternsSink sink;
     245             :     char currentStyle[kStyleLenMax+1];
     246           0 :     uprv_strncpy(currentStyle, style, kStyleLenMax);
     247           0 :     currentStyle[kStyleLenMax] = 0;
     248             : 
     249             :     for (;;) {
     250           0 :         ures_getAllItemsWithFallback(rb, currentStyle, sink, errorCode);
     251           0 :         if (U_FAILURE(errorCode) || sink.aliasedStyle[0] == 0 || uprv_strcmp(currentStyle, sink.aliasedStyle) == 0) {
     252           0 :             break;
     253             :         }
     254           0 :         uprv_strcpy(currentStyle, sink.aliasedStyle);
     255             :     }
     256           0 :     ures_close(rb);
     257           0 :     if (U_FAILURE(errorCode)) {
     258           0 :         return NULL;
     259             :     }
     260           0 :     if (sink.two.isEmpty() || sink.start.isEmpty() || sink.middle.isEmpty() || sink.end.isEmpty()) {
     261           0 :         errorCode = U_MISSING_RESOURCE_ERROR;
     262           0 :         return NULL;
     263             :     }
     264           0 :     ListFormatInternal* result = new ListFormatInternal(sink.two, sink.start, sink.middle, sink.end, errorCode);
     265           0 :     if (result == NULL) {
     266           0 :         errorCode = U_MEMORY_ALLOCATION_ERROR;
     267           0 :         return NULL;
     268             :     }
     269           0 :     if (U_FAILURE(errorCode)) {
     270           0 :         delete result;
     271           0 :         return NULL;
     272             :     }
     273           0 :     return result;
     274             : }
     275             : 
     276           0 : ListFormatter* ListFormatter::createInstance(UErrorCode& errorCode) {
     277           0 :     Locale locale;  // The default locale.
     278           0 :     return createInstance(locale, errorCode);
     279             : }
     280             : 
     281           0 : ListFormatter* ListFormatter::createInstance(const Locale& locale, UErrorCode& errorCode) {
     282           0 :     return createInstance(locale, STANDARD_STYLE, errorCode);
     283             : }
     284             : 
     285           0 : ListFormatter* ListFormatter::createInstance(const Locale& locale, const char *style, UErrorCode& errorCode) {
     286           0 :     Locale tempLocale = locale;
     287           0 :     const ListFormatInternal* listFormatInternal = getListFormatInternal(tempLocale, style, errorCode);
     288           0 :     if (U_FAILURE(errorCode)) {
     289           0 :         return NULL;
     290             :     }
     291           0 :     ListFormatter* p = new ListFormatter(listFormatInternal);
     292           0 :     if (p == NULL) {
     293           0 :         errorCode = U_MEMORY_ALLOCATION_ERROR;
     294           0 :         return NULL;
     295             :     }
     296           0 :     return p;
     297             : }
     298             : 
     299           0 : ListFormatter::ListFormatter(const ListFormatData& listFormatData, UErrorCode &errorCode) {
     300           0 :     owned = new ListFormatInternal(listFormatData, errorCode);
     301           0 :     data = owned;
     302           0 : }
     303             : 
     304           0 : ListFormatter::ListFormatter(const ListFormatInternal* listFormatterInternal) : owned(NULL), data(listFormatterInternal) {
     305           0 : }
     306             : 
     307           0 : ListFormatter::~ListFormatter() {
     308           0 :     delete owned;
     309           0 : }
     310             : 
     311             : /**
     312             :  * Joins first and second using the pattern pat.
     313             :  * On entry offset is an offset into first or -1 if offset unspecified.
     314             :  * On exit offset is offset of second in result if recordOffset was set
     315             :  * Otherwise if it was >=0 it is set to point into result where it used
     316             :  * to point into first. On exit, result is the join of first and second
     317             :  * according to pat. Any previous value of result gets replaced.
     318             :  */
     319           0 : static void joinStringsAndReplace(
     320             :         const SimpleFormatter& pat,
     321             :         const UnicodeString& first,
     322             :         const UnicodeString& second,
     323             :         UnicodeString &result,
     324             :         UBool recordOffset,
     325             :         int32_t &offset,
     326             :         UErrorCode& errorCode) {
     327           0 :     if (U_FAILURE(errorCode)) {
     328           0 :         return;
     329             :     }
     330           0 :     const UnicodeString *params[2] = {&first, &second};
     331             :     int32_t offsets[2];
     332             :     pat.formatAndReplace(
     333             :             params,
     334             :             UPRV_LENGTHOF(params),
     335             :             result,
     336             :             offsets,
     337             :             UPRV_LENGTHOF(offsets),
     338           0 :             errorCode);
     339           0 :     if (U_FAILURE(errorCode)) {
     340           0 :         return;
     341             :     }
     342           0 :     if (offsets[0] == -1 || offsets[1] == -1) {
     343           0 :         errorCode = U_INVALID_FORMAT_ERROR;
     344           0 :         return;
     345             :     }
     346           0 :     if (recordOffset) {
     347           0 :         offset = offsets[1];
     348           0 :     } else if (offset >= 0) {
     349           0 :         offset += offsets[0];
     350             :     }
     351             : }
     352             : 
     353           0 : UnicodeString& ListFormatter::format(
     354             :         const UnicodeString items[],
     355             :         int32_t nItems,
     356             :         UnicodeString& appendTo,
     357             :         UErrorCode& errorCode) const {
     358             :     int32_t offset;
     359           0 :     return format(items, nItems, appendTo, -1, offset, errorCode);
     360             : }
     361             : 
     362           0 : UnicodeString& ListFormatter::format(
     363             :         const UnicodeString items[],
     364             :         int32_t nItems,
     365             :         UnicodeString& appendTo,
     366             :         int32_t index,
     367             :         int32_t &offset,
     368             :         UErrorCode& errorCode) const {
     369           0 :     offset = -1;
     370           0 :     if (U_FAILURE(errorCode)) {
     371           0 :         return appendTo;
     372             :     }
     373           0 :     if (data == NULL) {
     374           0 :         errorCode = U_INVALID_STATE_ERROR;
     375           0 :         return appendTo;
     376             :     }
     377             : 
     378           0 :     if (nItems <= 0) {
     379           0 :         return appendTo;
     380             :     }
     381           0 :     if (nItems == 1) {
     382           0 :         if (index == 0) {
     383           0 :             offset = appendTo.length();
     384             :         }
     385           0 :         appendTo.append(items[0]);
     386           0 :         return appendTo;
     387             :     }
     388           0 :     UnicodeString result(items[0]);
     389           0 :     if (index == 0) {
     390           0 :         offset = 0;
     391             :     }
     392           0 :     joinStringsAndReplace(
     393           0 :             nItems == 2 ? data->twoPattern : data->startPattern,
     394             :             result,
     395           0 :             items[1],
     396             :             result,
     397             :             index == 1,
     398             :             offset,
     399           0 :             errorCode);
     400           0 :     if (nItems > 2) {
     401           0 :         for (int32_t i = 2; i < nItems - 1; ++i) {
     402           0 :              joinStringsAndReplace(
     403           0 :                      data->middlePattern,
     404             :                      result,
     405           0 :                      items[i],
     406             :                      result,
     407             :                      index == i,
     408             :                      offset,
     409           0 :                      errorCode);
     410             :         }
     411           0 :         joinStringsAndReplace(
     412           0 :                 data->endPattern,
     413             :                 result,
     414           0 :                 items[nItems - 1],
     415             :                 result,
     416           0 :                 index == nItems - 1,
     417             :                 offset,
     418           0 :                 errorCode);
     419             :     }
     420           0 :     if (U_SUCCESS(errorCode)) {
     421           0 :         if (offset >= 0) {
     422           0 :             offset += appendTo.length();
     423             :         }
     424           0 :         appendTo += result;
     425             :     }
     426           0 :     return appendTo;
     427             : }
     428             : 
     429             : U_NAMESPACE_END

Generated by: LCOV version 1.13