ICU-6433 currency parsing, case sensitive against symbol and ISO, case insensitive against name; parse against plural pattern using names only

X-SVN-Rev: 25540
This commit is contained in:
Xiaomei Ji 2009-03-10 20:53:27 +00:00
parent 2dfb80a9e1
commit 1f2dcc4fb2
5 changed files with 2068 additions and 2652 deletions

View File

@ -106,7 +106,8 @@ U_CALLCONV AffixPatternValueComparator(UHashTok val1, UHashTok val2) {
affix_1->posPrefixPatternForCurrency ==
affix_2->posPrefixPatternForCurrency &&
affix_1->posSuffixPatternForCurrency ==
affix_2->posSuffixPatternForCurrency;
affix_2->posSuffixPatternForCurrency &&
affix_1->patternType == affix_2->patternType;
}
@ -534,7 +535,8 @@ DecimalFormat::setupCurrencyAffixPatterns(UErrorCode& status) {
*fNegPrefixPattern,
*fNegSuffixPattern,
*fPosPrefixPattern,
*fPosSuffixPattern);
*fPosSuffixPattern,
UCURR_SYMBOL_NAME);
fAffixPatternsForCurrency->put("default", affixPtn, status);
}
@ -555,7 +557,8 @@ DecimalFormat::setupCurrencyAffixPatterns(UErrorCode& status) {
*fNegPrefixPattern,
*fNegSuffixPattern,
*fPosPrefixPattern,
*fPosSuffixPattern);
*fPosSuffixPattern,
UCURR_LONG_NAME);
fAffixPatternsForCurrency->put(*key, affixPtn, status);
}
}
@ -1626,7 +1629,7 @@ void DecimalFormat::parse(const UnicodeString& text,
if (!subparse(text,
fNegPrefixPattern, fNegSuffixPattern,
fPosPrefixPattern, fPosSuffixPattern,
FALSE,
FALSE, UCURR_SYMBOL_NAME,
parsePosition, digits, status, currency)) {
parsePosition.setIndex(backup);
return;
@ -1706,11 +1709,20 @@ DecimalFormat::parseForCurrency(const UnicodeString& text,
UBool tmpStatus[fgStatusLength];
ParsePosition tmpPos(origPos);
DigitList tmpDigitList;
UBool found = subparse(text,
fNegPrefixPattern, fNegSuffixPattern,
fPosPrefixPattern, fPosSuffixPattern,
TRUE,
tmpPos, tmpDigitList, tmpStatus, currency);
UBool found;
if (fStyle == NumberFormat::kPluralCurrencyStyle) {
found = subparse(text,
fNegPrefixPattern, fNegSuffixPattern,
fPosPrefixPattern, fPosSuffixPattern,
TRUE, UCURR_LONG_NAME,
tmpPos, tmpDigitList, tmpStatus, currency);
} else {
found = subparse(text,
fNegPrefixPattern, fNegSuffixPattern,
fPosPrefixPattern, fPosSuffixPattern,
TRUE, UCURR_SYMBOL_NAME,
tmpPos, tmpDigitList, tmpStatus, currency);
}
if (found) {
if (tmpPos.getIndex() > maxPosIndex) {
maxPosIndex = tmpPos.getIndex();
@ -1738,7 +1750,7 @@ DecimalFormat::parseForCurrency(const UnicodeString& text,
&affixPtn->negSuffixPatternForCurrency,
&affixPtn->posPrefixPatternForCurrency,
&affixPtn->posSuffixPatternForCurrency,
TRUE,
TRUE, affixPtn->patternType,
tmpPos, tmpDigitList, tmpStatus, currency);
if (result) {
found = true;
@ -1771,7 +1783,7 @@ DecimalFormat::parseForCurrency(const UnicodeString& text,
UBool result = subparse(text,
&fNegativePrefix, &fNegativeSuffix,
&fPositivePrefix, &fPositiveSuffix,
FALSE,
FALSE, UCURR_SYMBOL_NAME,
tmpPos_2, tmpDigitList_2, tmpStatus_2,
currency);
if (result) {
@ -1816,6 +1828,7 @@ is here if we change our minds.
* @param posPrefix positive prefix.
* @param posSuffix positive suffix.
* @param currencyParsing whether it is currency parsing or not.
* @param type the currency type to parse against, LONG_NAME only or not.
* @param parsePosition The position at which to being parsing. Upon
* return, the first unparsed character.
* @param digits the DigitList to set to the parsed value.
@ -1832,6 +1845,7 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
const UnicodeString* posPrefix,
const UnicodeString* posSuffix,
UBool currencyParsing,
int8_t type,
ParsePosition& parsePosition,
DigitList& digits, UBool* status,
UChar* currency) const
@ -1845,8 +1859,8 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
}
// Match positive and negative prefixes; prefer longest match.
int32_t posMatch = compareAffix(text, position, FALSE, TRUE, posPrefix, currencyParsing, currency);
int32_t negMatch = compareAffix(text, position, TRUE, TRUE, negPrefix,currencyParsing, currency);
int32_t posMatch = compareAffix(text, position, FALSE, TRUE, posPrefix, currencyParsing, type, currency);
int32_t negMatch = compareAffix(text, position, TRUE, TRUE, negPrefix,currencyParsing, type, currency);
if (posMatch >= 0 && negMatch >= 0) {
if (posMatch > negMatch) {
negMatch = -1;
@ -2061,10 +2075,10 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
// Match positive and negative suffixes; prefer longest match.
if (posMatch >= 0) {
posMatch = compareAffix(text, position, FALSE, FALSE, posSuffix, currencyParsing, currency);
posMatch = compareAffix(text, position, FALSE, FALSE, posSuffix, currencyParsing, type, currency);
}
if (negMatch >= 0) {
negMatch = compareAffix(text, position, TRUE, FALSE, negSuffix, currencyParsing, currency);
negMatch = compareAffix(text, position, TRUE, FALSE, negSuffix, currencyParsing, type, currency);
}
if (posMatch >= 0 && negMatch >= 0) {
if (posMatch > negMatch) {
@ -2124,6 +2138,7 @@ int32_t DecimalFormat::skipPadding(const UnicodeString& text, int32_t position)
* @param isPrefix
* @param affixPat affix pattern used for currency affix comparison.
* @param currencyParsing whether it is currency parsing or not
* @param type the currency type to parse against, LONG_NAME only or not.
* @param currency return value for parsed currency, for generic
* currency parsing mode, or null for normal parsing. In generic
* currency parsing mode, any currency is parsed, not just the
@ -2136,6 +2151,7 @@ int32_t DecimalFormat::compareAffix(const UnicodeString& text,
UBool isPrefix,
const UnicodeString* affixPat,
UBool currencyParsing,
int8_t type,
UChar* currency) const
{
const UnicodeString *patternToCompare;
@ -2143,7 +2159,7 @@ int32_t DecimalFormat::compareAffix(const UnicodeString& text,
(fCurrencySignCount > fgCurrencySignCountZero && currencyParsing)) {
if (affixPat != NULL) {
return compareComplexAffix(*affixPat, text, pos, currency);
return compareComplexAffix(*affixPat, text, pos, type, currency);
}
}
@ -2270,6 +2286,7 @@ int32_t DecimalFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) {
* @param affixPat pattern string
* @param input input text
* @param pos offset into input at which to begin matching
* @param type the currency type to parse against, LONG_NAME only or not.
* @param currency return value for parsed currency, for generic
* currency parsing mode, or null for normal parsing. In generic
* currency parsing mode, any currency is parsed, not just the
@ -2279,6 +2296,7 @@ int32_t DecimalFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) {
int32_t DecimalFormat::compareComplexAffix(const UnicodeString& affixPat,
const UnicodeString& text,
int32_t pos,
int8_t type,
UChar* currency) const
{
int32_t start = pos;
@ -2325,7 +2343,7 @@ int32_t DecimalFormat::compareComplexAffix(const UnicodeString& affixPat,
UChar curr[4];
UErrorCode ec = U_ZERO_ERROR;
// Delegate parse of display name => ISO code to Currency
uprv_parseCurrency(loc, text, ppos, curr, ec);
uprv_parseCurrency(loc, text, ppos, type, curr, ec);
// If parse succeeds, populate currency[0]
if (U_SUCCESS(ec) && ppos.getIndex() != pos) {
@ -4509,7 +4527,8 @@ DecimalFormat::copyHashForAffixPattern(const Hashtable* source,
value->negPrefixPatternForCurrency,
value->negSuffixPatternForCurrency,
value->posPrefixPatternForCurrency,
value->posSuffixPatternForCurrency);
value->posSuffixPatternForCurrency,
value->patternType);
target->put(UnicodeString(*key), copy, status);
if ( U_FAILURE(status) ) {
return;

View File

@ -634,6 +634,9 @@ ucurr_getPluralName(const UChar* currency,
#define NEED_TO_BE_DELETED 0x1
// TODO: a better way to define this?
#define MAX_CURRENCY_NAME_LEN 100
typedef struct {
const char* IsoCode; // key
UChar* currencyName; // value
@ -646,6 +649,11 @@ typedef struct {
#define MIN(a,b) (((a)<(b)) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a,b) (((a)<(b)) ? (b) : (a))
#endif
// Comparason function used in quick sort.
static int currencyNameComparator(const void* a, const void* b) {
const CurrencyNameStruct* currName_1 = (const CurrencyNameStruct*)a;
@ -677,9 +685,10 @@ static int currencyNameComparator(const void* a, const void* b) {
// For example, given locale as "en_US", the currency names get from resource
// bundle in "en_US" and "en" are duplicated. The fallback mechanism will count
// all currency names in "en_US" and "en".
static int32_t
getCurrencyNameCount(const char* loc) {
int32_t total_currency_count = 0;
static void
getCurrencyNameCount(const char* loc, int* total_currency_name_count, int* total_currency_symbol_count) {
*total_currency_name_count = 0;
*total_currency_symbol_count = 0;
const UChar* s = NULL;
char locale[ULOC_FULLNAME_CAPACITY];
uprv_strcpy(locale, loc);
@ -705,12 +714,13 @@ getCurrencyNameCount(const char* loc) {
ChoiceFormat fmt(s, ec2);
int32_t fmt_count;
fmt.getFormats(fmt_count);
total_currency_count += fmt_count;
*total_currency_symbol_count += fmt_count;
} else {
++total_currency_count; // currency symbol
++(*total_currency_symbol_count); // currency symbol
}
total_currency_count += 2; // long name and iso code
++(*total_currency_symbol_count); // iso code
++(*total_currency_name_count); // long name
ures_close(names);
}
@ -720,7 +730,7 @@ getCurrencyNameCount(const char* loc) {
n = ures_getSize(curr_p);
for (int32_t i=0; i<n; ++i) {
UResourceBundle* names = ures_getByIndex(curr_p, i, NULL, &ec3);
total_currency_count += ures_getSize(names);
*total_currency_name_count += ures_getSize(names);
ures_close(names);
}
ures_close(curr_p);
@ -731,7 +741,22 @@ getCurrencyNameCount(const char* loc) {
break;
}
}
return total_currency_count;
}
// TODO: locale dependent
static UChar*
toUpperCase(const UChar* source, int32_t len) {
UChar* dest = NULL;
UErrorCode ec = U_ZERO_ERROR;
int32_t destLen = u_strToUpper(dest, 0, source, len, NULL, &ec);
ec = U_ZERO_ERROR;
dest = (UChar*)uprv_malloc(sizeof(UChar) * MAX(destLen, len));
u_strToUpper(dest, destLen, source, len, NULL, &ec);
if (U_FAILURE(ec)) {
uprv_memcpy(dest, source, sizeof(UChar) * len);
}
return dest;
}
@ -741,8 +766,12 @@ getCurrencyNameCount(const char* loc) {
// "CurrencyPlural", enable fallback chain.
// return the malloc-ed currency name arrays and the total number of currency
// names in the array.
static CurrencyNameStruct*
collectCurrencyNames(const char* locale, int32_t* total_currency_count,
static void
collectCurrencyNames(const char* locale,
CurrencyNameStruct** currencyNames,
int32_t* total_currency_name_count,
CurrencyNameStruct** currencySymbols,
int32_t* total_currency_symbol_count,
UErrorCode& ec) {
// Look up the Currencies resource for the given locale.
UErrorCode ec2 = U_ZERO_ERROR;
@ -751,19 +780,21 @@ collectCurrencyNames(const char* locale, int32_t* total_currency_count,
uloc_getName(locale, loc, sizeof(loc), &ec2);
if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
ec = U_ILLEGAL_ARGUMENT_ERROR;
return NULL;
}
// Get maximum currency name count first.
int32_t max_currency_count = getCurrencyNameCount(loc);
getCurrencyNameCount(loc, total_currency_name_count, total_currency_symbol_count);
CurrencyNameStruct* currencyNames = (CurrencyNameStruct*)uprv_malloc
(sizeof(CurrencyNameStruct) * (max_currency_count));
*currencyNames = (CurrencyNameStruct*)uprv_malloc
(sizeof(CurrencyNameStruct) * (*total_currency_name_count));
*currencySymbols = (CurrencyNameStruct*)uprv_malloc
(sizeof(CurrencyNameStruct) * (*total_currency_symbol_count));
const UChar* s = NULL; // currency name
char* iso = NULL; // currency ISO code
*total_currency_count = 0;
*total_currency_name_count = 0;
*total_currency_symbol_count = 0;
UErrorCode ec3 = U_ZERO_ERROR;
UErrorCode ec4 = U_ZERO_ERROR;
@ -810,35 +841,36 @@ collectCurrencyNames(const char* locale, int32_t* total_currency_count,
int32_t length = formats[i].length();
UChar* name = (UChar*)uprv_malloc(sizeof(UChar)*length);
formats[i].extract(0, length, name);
currencyNames[*total_currency_count].IsoCode = iso;
currencyNames[*total_currency_count].currencyName = name;
currencyNames[*total_currency_count].flag = NEED_TO_BE_DELETED;
currencyNames[(*total_currency_count)++].currencyNameLen = length;
(*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
(*currencySymbols)[*total_currency_symbol_count].currencyName = name;
(*currencySymbols)[*total_currency_symbol_count].flag = NEED_TO_BE_DELETED;
(*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = length;
}
} else {
// Add currency symbol.
currencyNames[*total_currency_count].IsoCode = iso;
currencyNames[*total_currency_count].currencyName = (UChar*)s;
currencyNames[*total_currency_count].flag = 0;
currencyNames[(*total_currency_count)++].currencyNameLen = len;
(*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
(*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)s;
(*currencySymbols)[*total_currency_symbol_count].flag = 0;
(*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = len;
}
// Add currency long name.
s = ures_getStringByIndex(names, UCURR_LONG_NAME, &len, &ec2);
currencyNames[*total_currency_count].IsoCode = iso;
currencyNames[*total_currency_count].currencyName = (UChar*)s;
currencyNames[*total_currency_count].flag = 0;
currencyNames[(*total_currency_count)++].currencyNameLen = len;
(*currencyNames)[*total_currency_name_count].IsoCode = iso;
UChar* upperName = toUpperCase(s, len);
(*currencyNames)[*total_currency_name_count].currencyName = upperName;
(*currencyNames)[*total_currency_name_count].flag = NEED_TO_BE_DELETED;
(*currencyNames)[(*total_currency_name_count)++].currencyNameLen = len;
// put (iso, 3, and iso) in to array
// Add currency ISO code.
currencyNames[*total_currency_count].IsoCode = iso;
currencyNames[*total_currency_count].currencyName = (UChar*)uprv_malloc(sizeof(UChar)*3);
currencyNames[*total_currency_count].currencyName[0] = iso[0];
currencyNames[*total_currency_count].currencyName[1] = iso[1];
currencyNames[*total_currency_count].currencyName[2] = iso[2];
currencyNames[*total_currency_count].flag = NEED_TO_BE_DELETED;
currencyNames[(*total_currency_count)++].currencyNameLen = 3;
(*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
(*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)uprv_malloc(sizeof(UChar)*3);
(*currencySymbols)[*total_currency_symbol_count].currencyName[0] = iso[0];
(*currencySymbols)[*total_currency_symbol_count].currencyName[1] = iso[1];
(*currencySymbols)[*total_currency_symbol_count].currencyName[2] = iso[2];
(*currencySymbols)[*total_currency_symbol_count].flag = NEED_TO_BE_DELETED;
(*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = 3;
ures_close(names);
}
@ -867,10 +899,11 @@ collectCurrencyNames(const char* locale, int32_t* total_currency_count,
// TODO: remove duplicates between singular name and
// currency long name?
s = ures_getStringByIndex(names, j, &len, &ec3);
currencyNames[*total_currency_count].IsoCode = iso;
currencyNames[*total_currency_count].currencyName = (UChar*)s;
currencyNames[*total_currency_count].flag = 0;
currencyNames[(*total_currency_count)++].currencyNameLen = len;
(*currencyNames)[*total_currency_name_count].IsoCode = iso;
UChar* upperName = toUpperCase(s, len);
(*currencyNames)[*total_currency_name_count].currencyName = upperName;
(*currencyNames)[*total_currency_name_count].flag = NEED_TO_BE_DELETED;
(*currencyNames)[(*total_currency_name_count)++].currencyNameLen = len;
}
ures_close(names);
}
@ -887,42 +920,51 @@ collectCurrencyNames(const char* locale, int32_t* total_currency_count,
uhash_close(currencyPluralIsoCodes);
// quick sort the struct
qsort(currencyNames, *total_currency_count, sizeof(CurrencyNameStruct),
currencyNameComparator);
qsort(*currencyNames, *total_currency_name_count,
sizeof(CurrencyNameStruct), currencyNameComparator);
qsort(*currencySymbols, *total_currency_symbol_count,
sizeof(CurrencyNameStruct), currencyNameComparator);
#ifdef UCURR_DEBUG
for (int32_t index = 0; index < *total_currency_count; ++index) {
printf("currency name count: %d\n", *total_currency_name_count);
for (int32_t index = 0; index < *total_currency_name_count; ++index) {
printf("index: %d\n", index);
printf("iso: %s\n", currencyNames[index].IsoCode);
printf("iso: %s\n", (*currencyNames)[index].IsoCode);
printf("currencyName:");
for (int32_t i = 0; i < currencyNames[index].currencyNameLen; ++i) {
printf("%c", (unsigned char)currencyNames[index].currencyName[i]);
for (int32_t i = 0; i < (*currencyNames)[index].currencyNameLen; ++i) {
printf("%c", (unsigned char)(*currencyNames)[index].currencyName[i]);
}
printf("\n");
printf("len: %d\n", currencyNames[index].currencyNameLen);
printf("len: %d\n", (*currencyNames)[index].currencyNameLen);
}
printf("currency symbol count: %d\n", *total_currency_symbol_count);
for (int32_t index = 0; index < *total_currency_symbol_count; ++index) {
printf("index: %d\n", index);
printf("iso: %s\n", (*currencySymbols)[index].IsoCode);
printf("currencySymbol:");
for (int32_t i = 0; i < (*currencySymbols)[index].currencyNameLen; ++i) {
printf("%c", (unsigned char)(*currencySymbols)[index].currencyName[i]);
}
printf("\n");
printf("len: %d\n", (*currencySymbols)[index].currencyNameLen);
}
printf("currency count: %d\n", *total_currency_count);
#endif
return currencyNames;
}
// @param currencyNames: currency names array
// @param indexInCurrencyNames: the index of the character in currency names
// array against which the comparison is done
// @param text: input text to compare against
// @param pos: the position of character in input text to compare against
// @param key: input text char to compare against
// @param begin(IN/OUT): the begin index of matching range in currency names array
// @param end(IN/OUT): the end index of matching range in currency names array.
static int32_t
binarySearch(const CurrencyNameStruct* currencyNames,
int32_t indexInCurrencyNames,
const UnicodeString* text, int32_t pos,
const UChar key,
int32_t* begin, int32_t* end) {
#ifdef UCURR_DEBUG
printf("pos = %d\n", pos);
printf("key = %x\n", key);
#endif
UChar key = text->charAt(pos);
int32_t first = *begin;
int32_t last = *end;
while (first <= last) {
@ -1024,7 +1066,7 @@ binarySearch(const CurrencyNameStruct* currencyNames,
// Linear search "text" in "currencyNames".
// @param begin, end: the begin and end index in currencyNames, within which
// range should the search be performed.
// @param startPos: the comparison start position in text
// @param textLen: the length of the text to be compared
// @param maxMatchLen(IN/OUT): passing in the computed max matching length
// pass out the new max matching length
// @param maxMatchIndex: the index in currencyName which has the longest
@ -1032,13 +1074,12 @@ binarySearch(const CurrencyNameStruct* currencyNames,
static void
linearSearch(const CurrencyNameStruct* currencyNames,
int32_t begin, int32_t end,
const UnicodeString* text, int32_t startPos,
const UChar* text, int32_t textLen,
int32_t *maxMatchLen, int32_t* maxMatchIndex) {
for (int32_t index = begin; index <= end; ++index) {
int32_t len = currencyNames[index].currencyNameLen;
// TODO: case in-sensitve? but case-sensitive for ISO code /symbol?
if (len > *maxMatchLen &&
text->compare(startPos, len, currencyNames[index].currencyName) == 0) {
if (len > *maxMatchLen && len <= textLen &&
uprv_memcmp(currencyNames[index].currencyName, text, len * sizeof(UChar)) == 0) {
*maxMatchIndex = index;
*maxMatchLen = len;
#ifdef UCURR_DEBUG
@ -1053,7 +1094,7 @@ linearSearch(const CurrencyNameStruct* currencyNames,
// Find longest match between "text" and currency names in "currencyNames".
// @param total_currency_count: total number of currency names in CurrencyNames.
// @param start: the comparison start position in text
// @param textLen: the length of the text to be compared
// @param maxMatchLen: passing in the computed max matching length
// pass out the new max matching length
// @param maxMatchIndex: the index in currencyName which has the longest
@ -1061,7 +1102,7 @@ linearSearch(const CurrencyNameStruct* currencyNames,
static void
searchCurrencyName(const CurrencyNameStruct* currencyNames,
int32_t total_currency_count,
const UnicodeString* text, int32_t start,
const UChar* text, int32_t textLen,
int32_t* maxMatchLen, int32_t* maxMatchIndex) {
*maxMatchIndex = -1;
*maxMatchLen = 0;
@ -1082,25 +1123,25 @@ searchCurrencyName(const CurrencyNameStruct* currencyNames,
// maximum matching).
// The 4th round returns the same range (the maximum matching is "BBEX").
// The 5th round returns no matching range.
for (int32_t index = start; index < text->length(); ++index) {
for (int32_t index = 0; index < textLen; ++index) {
// matchIndex saves the one with exact match till the current point.
// [binarySearchBegin, binarySearchEnd] saves the matching range.
matchIndex = binarySearch(currencyNames, index - start,
text, index,
matchIndex = binarySearch(currencyNames, index,
text[index],
&binarySearchBegin, &binarySearchEnd);
if (binarySearchBegin == -1) { // did not find the range
break;
}
if (matchIndex != -1) {
// find an exact match for text from text[start] to text[index]
// find an exact match for text from text[0] to text[index]
// in currencyNames array.
*maxMatchLen = index - start + 1;
*maxMatchLen = index + 1;
*maxMatchIndex = matchIndex;
}
if (binarySearchEnd - binarySearchBegin < LINEAR_SEARCH_THRESHOLD) {
// linear search if within threshold.
linearSearch(currencyNames, binarySearchBegin, binarySearchEnd,
text, start,
text, textLen,
maxMatchLen, maxMatchIndex);
break;
}
@ -1111,8 +1152,12 @@ searchCurrencyName(const CurrencyNameStruct* currencyNames,
//========================= currency name cache =====================
typedef struct {
char locale[ULOC_FULLNAME_CAPACITY]; //key
// currency names, case insensitive
CurrencyNameStruct* currencyNames; // value
int32_t totalCurrencyNameCount; // currency name count
// currency symbols and ISO code, case sensitive
CurrencyNameStruct* currencySymbols; // value
int32_t totalCurrencySymbolCount; // count
// reference count.
// reference count is set to 1 when an entry is put to cache.
// it increases by 1 before accessing, and decreased by 1 after accessing.
@ -1145,6 +1190,7 @@ deleteCurrencyNames(CurrencyNameStruct* currencyNames, int32_t count) {
static void
deleteCacheEntry(CurrencyNameCacheEntry* entry) {
deleteCurrencyNames(entry->currencyNames, entry->totalCurrencyNameCount);
deleteCurrencyNames(entry->currencySymbols, entry->totalCurrencySymbolCount);
uprv_free(entry);
}
@ -1166,6 +1212,7 @@ U_CFUNC void
uprv_parseCurrency(const char* locale,
const U_NAMESPACE_QUALIFIER UnicodeString& text,
U_NAMESPACE_QUALIFIER ParsePosition& pos,
int8_t type,
UChar* result,
UErrorCode& ec)
{
@ -1175,8 +1222,10 @@ uprv_parseCurrency(const char* locale,
return;
}
int32_t total_currency_count = 0;
int32_t total_currency_name_count = 0;
CurrencyNameStruct* currencyNames = NULL;
int32_t total_currency_symbol_count = 0;
CurrencyNameStruct* currencySymbols = NULL;
CurrencyNameCacheEntry* cacheEntry = NULL;
umtx_lock(NULL);
@ -1193,12 +1242,14 @@ uprv_parseCurrency(const char* locale,
if (found != -1) {
cacheEntry = currCache[found];
currencyNames = cacheEntry->currencyNames;
total_currency_count = cacheEntry->totalCurrencyNameCount;
total_currency_name_count = cacheEntry->totalCurrencyNameCount;
currencySymbols = cacheEntry->currencySymbols;
total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
++(cacheEntry->refCount);
}
umtx_unlock(NULL);
if (found == -1) {
currencyNames = collectCurrencyNames(locale, &total_currency_count, ec);
collectCurrencyNames(locale, &currencyNames, &total_currency_name_count, &currencySymbols, &total_currency_symbol_count, ec);
if (U_FAILURE(ec)) {
return;
}
@ -1230,31 +1281,66 @@ uprv_parseCurrency(const char* locale,
currCache[currentCacheEntryIndex] = cacheEntry;
uprv_strcpy(cacheEntry->locale, locale);
cacheEntry->currencyNames = currencyNames;
cacheEntry->totalCurrencyNameCount = total_currency_count;
cacheEntry->totalCurrencyNameCount = total_currency_name_count;
cacheEntry->currencySymbols = currencySymbols;
cacheEntry->totalCurrencySymbolCount = total_currency_symbol_count;
cacheEntry->refCount = 2; // one for cache, one for reference
currentCacheEntryIndex = (currentCacheEntryIndex + 1) % CURRENCY_NAME_CACHE_NUM;
ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cache_cleanup);
} else {
uprv_free(currencyNames);
deleteCurrencyNames(currencyNames, total_currency_name_count);
deleteCurrencyNames(currencySymbols, total_currency_symbol_count);
cacheEntry = currCache[found];
currencyNames = cacheEntry->currencyNames;
total_currency_count = cacheEntry->totalCurrencyNameCount;
total_currency_name_count = cacheEntry->totalCurrencyNameCount;
currencySymbols = cacheEntry->currencySymbols;
total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
++(cacheEntry->refCount);
}
umtx_unlock(NULL);
}
int32_t start = pos.getIndex();
UChar inputText[MAX_CURRENCY_NAME_LEN];
UChar upperText[MAX_CURRENCY_NAME_LEN];
int32_t textLen = MIN(MAX_CURRENCY_NAME_LEN, text.length() - start);
text.extract(start, textLen, inputText);
UErrorCode ec1 = U_ZERO_ERROR;
textLen = u_strToUpper(upperText, MAX_CURRENCY_NAME_LEN, inputText, textLen, NULL, &ec1);
int32_t max = 0;
int32_t matchIndex = -1;
int32_t start = pos.getIndex();
searchCurrencyName(currencyNames, total_currency_count,
&text, start, &max, &matchIndex);
// case in-sensitive comparision against currency names
searchCurrencyName(currencyNames, total_currency_name_count,
upperText, textLen, &max, &matchIndex);
if (matchIndex != -1) {
u_charsToUChars(currencyNames[matchIndex].IsoCode, result, 4);
#ifdef UCURR_DEBUG
printf("search in names, max = %d, matchIndex = %d\n", max, matchIndex);
#endif
int32_t maxInSymbol = 0;
int32_t matchIndexInSymbol = -1;
if (type != UCURR_LONG_NAME) { // not name only
// case sensitive comparison against currency symbols and ISO code.
searchCurrencyName(currencySymbols, total_currency_symbol_count,
inputText, textLen,
&maxInSymbol, &matchIndexInSymbol);
}
#ifdef UCURR_DEBUG
printf("search in symbols, maxInSymbol = %d, matchIndexInSymbol = %d\n", maxInSymbol, matchIndexInSymbol);
#endif
if (max >= maxInSymbol && matchIndex != -1) {
u_charsToUChars(currencyNames[matchIndex].IsoCode, result, 4);
pos.setIndex(start + max);
} else if (maxInSymbol >= max && matchIndexInSymbol != -1) {
u_charsToUChars(currencySymbols[matchIndexInSymbol].IsoCode, result, 4);
pos.setIndex(start + maxInSymbol);
}
// decrease reference count
umtx_lock(NULL);
--(cacheEntry->refCount);
@ -1262,8 +1348,6 @@ uprv_parseCurrency(const char* locale,
deleteCacheEntry(cacheEntry);
}
umtx_unlock(NULL);
pos.setIndex(start + max);
}

View File

@ -1,6 +1,6 @@
/*
**********************************************************************
* Copyright (c) 2002-2008, International Business Machines
* Copyright (c) 2002-2009, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
*/
@ -40,6 +40,7 @@ uprv_getStaticCurrencyName(const UChar* iso, const char* loc,
* text to match; must have 0 <= pos.getIndex() < text.length();
* on output, the position after the last matched character. If
* the parse fails, the position in unchanged upon output.
* @param type currency type to parse against, LONG_NAME only or not
* @return the ISO 4217 code, as a string, of the best match, or
* null if there is no match
*
@ -49,6 +50,7 @@ U_CFUNC void
uprv_parseCurrency(const char* locale,
const U_NAMESPACE_QUALIFIER UnicodeString& text,
U_NAMESPACE_QUALIFIER ParsePosition& pos,
int8_t type,
UChar* result,
UErrorCode& ec);

View File

@ -1833,6 +1833,7 @@ private:
const UnicodeString* posPrefix,
const UnicodeString* posSuffix,
UBool currencyParsing,
int8_t type,
ParsePosition& parsePosition,
DigitList& digits, UBool* status,
UChar* currency) const;
@ -1856,6 +1857,7 @@ private:
UBool isPrefix,
const UnicodeString* affixPat,
UBool currencyParsing,
int8_t type,
UChar* currency) const;
static int32_t compareSimpleAffix(const UnicodeString& affix,
@ -1869,6 +1871,7 @@ private:
int32_t compareComplexAffix(const UnicodeString& affixPat,
const UnicodeString& input,
int32_t pos,
int8_t type,
UChar* currency) const;
static int32_t match(const UnicodeString& text, int32_t pos, UChar32 ch);
@ -2042,15 +2045,18 @@ private:
UnicodeString posPrefixPatternForCurrency;
// positive suffix pattern
UnicodeString posSuffixPatternForCurrency;
int8_t patternType;
AffixPatternsForCurrency(const UnicodeString& negPrefix,
const UnicodeString& negSuffix,
const UnicodeString& posPrefix,
const UnicodeString& posSuffix) {
const UnicodeString& posSuffix,
int8_t type) {
negPrefixPatternForCurrency = negPrefix;
negSuffixPatternForCurrency = negSuffix;
posPrefixPatternForCurrency = posPrefix;
posSuffixPatternForCurrency = posSuffix;
patternType = type;
}
};

File diff suppressed because it is too large Load Diff