void PNamesBuilderImpl::writeCSourceFile(const char *path, UErrorCode &errorCode) { if(U_FAILURE(errorCode)) { return; } FILE *f=usrc_create(path, "propname_data.h", "icu/tools/unicode/c/genprops/pnamesbuilder.cpp"); if(f==NULL) { errorCode=U_FILE_ACCESS_ERROR; return; } fputs("#ifndef INCLUDED_FROM_PROPNAME_CPP\n" "# error This file must be #included from propname.cpp only.\n" "#endif\n\n", f); fputs("U_NAMESPACE_BEGIN\n\n", f); usrc_writeArray(f, "const int32_t PropNameData::indexes[%ld]={", indexes, 32, PropNameData::IX_COUNT, "};\n\n"); usrc_writeArray(f, "const int32_t PropNameData::valueMaps[%ld]={\n", valueMaps.getBuffer(), 32, valueMaps.size(), "\n};\n\n"); usrc_writeArray(f, "const uint8_t PropNameData::bytesTries[%ld]={\n", bytesTries.data(), 8, bytesTries.length(), "\n};\n\n"); usrc_writeArrayOfMostlyInvChars( f, "const char PropNameData::nameGroups[%ld]={\n", nameGroups.data(), nameGroups.length(), "\n};\n\n"); fputs("U_NAMESPACE_END\n", f); fclose(f); }
void CompactData::populate(const Locale &locale, const char *nsName, CompactStyle compactStyle, CompactType compactType, UErrorCode &status) { CompactDataSink sink(*this); LocalUResourceBundlePointer rb(ures_open(nullptr, locale.getName(), &status)); if (U_FAILURE(status)) { return; } bool nsIsLatn = strcmp(nsName, "latn") == 0; bool compactIsShort = compactStyle == CompactStyle::UNUM_SHORT; // Fall back to latn numbering system and/or short compact style. CharString resourceKey; getResourceBundleKey(nsName, compactStyle, compactType, resourceKey, status); UErrorCode localStatus = U_ZERO_ERROR; ures_getAllItemsWithFallback(rb.getAlias(), resourceKey.data(), sink, localStatus); if (isEmpty && !nsIsLatn) { getResourceBundleKey("latn", compactStyle, compactType, resourceKey, status); localStatus = U_ZERO_ERROR; ures_getAllItemsWithFallback(rb.getAlias(), resourceKey.data(), sink, localStatus); } if (isEmpty && !compactIsShort) { getResourceBundleKey(nsName, CompactStyle::UNUM_SHORT, compactType, resourceKey, status); localStatus = U_ZERO_ERROR; ures_getAllItemsWithFallback(rb.getAlias(), resourceKey.data(), sink, localStatus); } if (isEmpty && !nsIsLatn && !compactIsShort) { getResourceBundleKey("latn", CompactStyle::UNUM_SHORT, compactType, resourceKey, status); localStatus = U_ZERO_ERROR; ures_getAllItemsWithFallback(rb.getAlias(), resourceKey.data(), sink, localStatus); } // The last fallback should be guaranteed to return data. if (isEmpty) { status = U_INTERNAL_PROGRAM_ERROR; } }
DictionaryMatcher * ICULanguageBreakFactory::loadDictionaryMatcherFor(UScriptCode script, int32_t /* brkType */) { UErrorCode status = U_ZERO_ERROR; // open root from brkitr tree. UResourceBundle *b = ures_open(U_ICUDATA_BRKITR, "", &status); b = ures_getByKeyWithFallback(b, "dictionaries", b, &status); int32_t dictnlength = 0; const UChar *dictfname = ures_getStringByKeyWithFallback(b, uscript_getShortName(script), &dictnlength, &status); if (U_FAILURE(status)) { ures_close(b); return NULL; } CharString dictnbuf; CharString ext; const UChar *extStart = u_memrchr(dictfname, 0x002e, dictnlength); // last dot if (extStart != NULL) { int32_t len = (int32_t)(extStart - dictfname); ext.appendInvariantChars(UnicodeString(FALSE, extStart + 1, dictnlength - len - 1), status); dictnlength = len; } dictnbuf.appendInvariantChars(UnicodeString(FALSE, dictfname, dictnlength), status); ures_close(b); UDataMemory *file = udata_open(U_ICUDATA_BRKITR, ext.data(), dictnbuf.data(), &status); if (U_SUCCESS(status)) { // build trie const uint8_t *data = (const uint8_t *)udata_getMemory(file); const int32_t *indexes = (const int32_t *)data; const int32_t offset = indexes[DictionaryData::IX_STRING_TRIE_OFFSET]; const int32_t trieType = indexes[DictionaryData::IX_TRIE_TYPE] & DictionaryData::TRIE_TYPE_MASK; DictionaryMatcher *m = NULL; if (trieType == DictionaryData::TRIE_TYPE_BYTES) { const int32_t transform = indexes[DictionaryData::IX_TRANSFORM]; const char *characters = (const char *)(data + offset); m = new BytesDictionaryMatcher(characters, transform, file); } else if (trieType == DictionaryData::TRIE_TYPE_UCHARS) { const UChar *characters = (const UChar *)(data + offset); m = new UCharsDictionaryMatcher(characters, file); } if (m == NULL) { // no matcher exists to take ownership - either we are an invalid // type or memory allocation failed udata_close(file); } return m; } else if (dictfname != NULL) { // we don't have a dictionary matcher. // returning NULL here will cause us to fail to find a dictionary break engine, as expected status = U_ZERO_ERROR; return NULL; } return NULL; }
PluralMapBase::Category PluralMapBase::toCategory(const UnicodeString &pluralForm) { CharString cCategory; UErrorCode status = U_ZERO_ERROR; cCategory.appendInvariantChars(pluralForm, status); return U_FAILURE(status) ? NONE : toCategory(cCategory.data()); }
static UnicodeString loadNumericDateFormatterPattern( const UResourceBundle *resource, const char *pattern, UErrorCode &status) { UnicodeString result; if (U_FAILURE(status)) { return result; } CharString chs; chs.append("durationUnits", status) .append("/", status).append(pattern, status); LocalUResourceBundlePointer patternBundle( ures_getByKeyWithFallback( resource, chs.data(), NULL, &status)); if (U_FAILURE(status)) { return result; } getString(patternBundle.getAlias(), result, status); // Replace 'h' with 'H' int32_t len = result.length(); UChar *buffer = result.getBuffer(len); for (int32_t i = 0; i < len; ++i) { if (buffer[i] == 0x68) { // 'h' buffer[i] = 0x48; // 'H' } } result.releaseBuffer(len); return result; }
const Hashtable* LocaleUtility::getAvailableLocaleNames(const UnicodeString& bundleID) { // LocaleUtility_cache is a hash-of-hashes. The top-level keys // are path strings ('bundleID') passed to // ures_openAvailableLocales. The top-level values are // second-level hashes. The second-level keys are result strings // from ures_openAvailableLocales. The second-level values are // garbage ((void*)1 or other random pointer). UErrorCode status = U_ZERO_ERROR; umtx_initOnce(LocaleUtilityInitOnce, locale_utility_init, status); Hashtable *cache = LocaleUtility_cache; if (cache == NULL) { // Catastrophic failure. return NULL; } Hashtable* htp; umtx_lock(NULL); htp = (Hashtable*) cache->get(bundleID); umtx_unlock(NULL); if (htp == NULL) { htp = new Hashtable(status); if (htp && U_SUCCESS(status)) { CharString cbundleID; cbundleID.appendInvariantChars(bundleID, status); const char* path = cbundleID.isEmpty() ? NULL : cbundleID.data(); UEnumeration *uenum = ures_openAvailableLocales(path, &status); for (;;) { const UChar* id = uenum_unext(uenum, NULL, &status); if (id == NULL) { break; } htp->put(UnicodeString(id), (void*)htp, status); } uenum_close(uenum); if (U_FAILURE(status)) { delete htp; return NULL; } umtx_lock(NULL); Hashtable *t = static_cast<Hashtable *>(cache->get(bundleID)); if (t != NULL) { // Another thread raced through this code, creating the cache entry first. // Discard ours and return theirs. umtx_unlock(NULL); delete htp; htp = t; } else { cache->put(bundleID, (void*)htp, status); umtx_unlock(NULL); } } } return htp; }
static void load(const Locale& inLocale, CDFLocaleData* result, UErrorCode& status) { LocalPointer<NumberingSystem> ns(NumberingSystem::createInstance(inLocale, status)); if (U_FAILURE(status)) { return; } const char* nsName = ns->getName(); LocalUResourceBundlePointer resource(ures_open(NULL, inLocale.getName(), &status)); if (U_FAILURE(status)) { return; } CmptDecDataSink sink(*result); sink.isFallback = FALSE; // First load the number elements data if nsName is not Latin. if (uprv_strcmp(nsName, gLatnTag) != 0) { sink.isLatin = FALSE; CharString path; path.append(gNumberElementsTag, status) .append('/', status) .append(nsName, status); ures_getAllItemsWithFallback(resource.getAlias(), path.data(), sink, status); if (status == U_MISSING_RESOURCE_ERROR) { // Silently ignore and use Latin status = U_ZERO_ERROR; } else if (U_FAILURE(status)) { return; } sink.isFallback = TRUE; } // Now load Latin. sink.isLatin = TRUE; ures_getAllItemsWithFallback(resource.getAlias(), gLatnPath, sink, status); if (U_FAILURE(status)) return; // If longData is empty, default it to be equal to shortData if (result->longData.isEmpty()) { result->longData.setToBogus(); } // Check for "other" variants in each of the three data classes, and resolve missing elements. if (!result->longData.isBogus()) { checkForOtherVariants(&result->longData, status); if (U_FAILURE(status)) return; fillInMissing(&result->longData); } checkForOtherVariants(&result->shortData, status); if (U_FAILURE(status)) return; fillInMissing(&result->shortData); // TODO: Enable this statement when currency support is added // checkForOtherVariants(&result->shortCurrencyData, status); // if (U_FAILURE(status)) return; // fillInMissing(&result->shortCurrencyData); }
void TimeUnitFormat::checkConsistency(UTimeUnitFormatStyle style, const char* key, UErrorCode& err) { if (U_FAILURE(err)) { return; } // there should be patterns for each plural rule in each time unit. // For each time unit, // for each plural rule, following is unit pattern fall-back rule: // ( for example: "one" hour ) // look for its unit pattern in its locale tree. // if pattern is not found in its own locale, such as de_DE, // look for the pattern in its parent, such as de, // keep looking till found or till root. // if the pattern is not found in root either, // fallback to plural count "other", // look for the pattern of "other" in the locale tree: // "de_DE" to "de" to "root". // If not found, fall back to value of // static variable DEFAULT_PATTERN_FOR_xxx, such as "{0} h". // // Following is consistency check to create pattern for each // plural rule in each time unit using above fall-back rule. // StringEnumeration* keywords = getPluralRules().getKeywords(err); if (U_SUCCESS(err)) { const UnicodeString* pluralCount; while ((pluralCount = keywords->snext(err)) != NULL) { if ( U_SUCCESS(err) ) { for (int32_t i = 0; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; ++i) { // for each time unit, // get all the patterns for each plural rule in this locale. Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i]; if ( countToPatterns == NULL ) { countToPatterns = initHash(err); if (U_FAILURE(err)) { delete countToPatterns; return; } fTimeUnitToCountToPatterns[i] = countToPatterns; } MessageFormat** formatters = (MessageFormat**)countToPatterns->get(*pluralCount); if( formatters == NULL || formatters[style] == NULL ) { // look through parents const char* localeName = getLocaleID(err); CharString pluralCountChars; pluralCountChars.appendInvariantChars(*pluralCount, err); searchInLocaleChain(style, key, localeName, (TimeUnit::UTimeUnitFields)i, *pluralCount, pluralCountChars.data(), countToPatterns, err); } } } } } delete keywords; }
static void strToLocale( const UnicodeString &str, void *localePtr, UErrorCode &status) { if (U_FAILURE(status)) { return; } CharString localeStr; localeStr.appendInvariantChars(str, status); *static_cast<Locale *>(localePtr) = Locale(localeStr.data()); }
void CurrencyAffixInfo::set( const char *locale, const PluralRules *rules, const UChar *currency, UErrorCode &status) { if (U_FAILURE(status)) { return; } fIsDefault = FALSE; if (currency == NULL) { fSymbol.setTo(gDefaultSymbols, 1); fISO.setTo(gDefaultSymbols, 2); fLong.remove(); fLong.append(gDefaultSymbols, 3); fIsDefault = TRUE; return; } int32_t len; UBool unusedIsChoice; const UChar *symbol = ucurr_getName( currency, locale, UCURR_SYMBOL_NAME, &unusedIsChoice, &len, &status); if (U_FAILURE(status)) { return; } fSymbol.setTo(symbol, len); fISO.setTo(currency, u_strlen(currency)); fLong.remove(); StringEnumeration* keywords = rules->getKeywords(status); if (U_FAILURE(status)) { return; } const UnicodeString* pluralCount; while ((pluralCount = keywords->snext(status)) != NULL) { CharString pCount; pCount.appendInvariantChars(*pluralCount, status); const UChar *pluralName = ucurr_getPluralName( currency, locale, &unusedIsChoice, pCount.data(), &len, &status); fLong.setVariant(pCount.data(), UnicodeString(pluralName, len), status); } delete keywords; }
static void strToDouble( const UnicodeString &str, void *doublePtr, UErrorCode &status) { if (U_FAILURE(status)) { return; } CharString buffer; buffer.appendInvariantChars(str, status); if (U_FAILURE(status)) { return; } *static_cast<double *>(doublePtr) = atof(buffer.data()); }
// getCDFUnitFallback returns a pointer to the prefix-suffix pair for a given // variant and log10 value within table. If the given variant doesn't exist, it // falls back to the OTHER variant. Therefore, this method will always return // some non-NULL value. static const CDFUnit* getCDFUnitFallback(const UHashtable* table, const UnicodeString& variant, int32_t log10Value) { CharString cvariant; UErrorCode status = U_ZERO_ERROR; const CDFUnit *cdfUnit = NULL; cvariant.appendInvariantChars(variant, status); if (!U_FAILURE(status)) { cdfUnit = (const CDFUnit*) uhash_get(table, cvariant.data()); } if (cdfUnit == NULL) { cdfUnit = (const CDFUnit*) uhash_get(table, gOther); } return &cdfUnit[log10Value]; }
void PNamesBuilderImpl::writeBinaryData(const char *path, UBool withCopyright, UErrorCode &errorCode) { if(U_FAILURE(errorCode)) { return; } UNewDataMemory *pdata=udata_create(path, PNAME_DATA_TYPE, PNAME_DATA_NAME, &dataInfo, withCopyright ? U_COPYRIGHT_STRING : 0, &errorCode); if(U_FAILURE(errorCode)) { fprintf(stderr, "genprops: udata_create(%s, pnames.icu) failed - %s\n", path, u_errorName(errorCode)); return; } udata_writeBlock(pdata, indexes, PropNameData::IX_COUNT*4); udata_writeBlock(pdata, valueMaps.getBuffer(), valueMaps.size()*4); udata_writeBlock(pdata, bytesTries.data(), bytesTries.length()); udata_writeBlock(pdata, nameGroups.data(), nameGroups.length()); int32_t dataLength=(int32_t)udata_finish(pdata, &errorCode); if(dataLength!=indexes[PropNameData::IX_TOTAL_SIZE]) { fprintf(stderr, "udata_finish(pnames.icu) reports %ld bytes written but should be %ld\n", (long)dataLength, (long)indexes[PropNameData::IX_TOTAL_SIZE]); errorCode=U_INTERNAL_PROGRAM_ERROR; } }
void NamesPropsBuilder::setProps(const UniProps &props, const UnicodeSet &newValues, UErrorCode &errorCode) { if(U_FAILURE(errorCode)) { return; } if(!newValues.contains(UCHAR_NAME) && !newValues.contains(PPUCD_NAME_ALIAS)) { return; } U_ASSERT(props.start==props.end); const char *names[4]={ NULL, NULL, NULL, NULL }; int16_t lengths[4]={ 0, 0, 0, 0 }; /* get the character name */ if(props.name!=NULL) { names[0]=props.name; lengths[0]=(int16_t)uprv_strlen(props.name); parseName(names[0], lengths[0]); } CharString buffer; if(props.nameAlias!=NULL) { /* * Only use "correction" aliases for now, from Unicode 6.1 NameAliases.txt with 3 fields per line. * TODO: Work on ticket #8963 to deal with multiple type:alias pairs per character. */ const char *corr=uprv_strstr(props.nameAlias, "correction="); if(corr!=NULL) { corr+=11; // skip "correction=" const char *limit=uprv_strchr(corr, ','); if(limit!=NULL) { buffer.append(corr, limit-corr, errorCode); names[3]=buffer.data(); lengths[3]=(int16_t)(limit-corr); } else { names[3]=corr; lengths[3]=(int16_t)uprv_strlen(corr); } parseName(names[3], lengths[3]); } } addLine(props.start, names, lengths, LENGTHOF(names)); }
U_DRAFT const char * U_EXPORT2 ufmt_getDecNumChars(UFormattable *fmt, int32_t *len, UErrorCode *status) { if(U_FAILURE(*status)) { return ""; } Formattable *obj = Formattable::fromUFormattable(fmt); CharString *charString = obj->internalGetCharString(*status); if(U_FAILURE(*status)) { return ""; } if(charString == NULL) { *status = U_MEMORY_ALLOCATION_ERROR; return ""; } else { if(len!=NULL) { *len = charString->length(); } return charString->data(); } }
static int32_t toEnum( const Numberformattesttuple_EnumConversion *table, int32_t tableLength, const UnicodeString &str, UErrorCode &status) { if (U_FAILURE(status)) { return 0; } CharString cstr; cstr.appendInvariantChars(str, status); if (U_FAILURE(status)) { return 0; } for (int32_t i = 0; i < tableLength; ++i) { if (uprv_strcmp(cstr.data(), table[i].str) == 0) { return table[i].value; } } status = U_ILLEGAL_ARGUMENT_ERROR; return 0; }
ENumberFormatTestTupleField NumberFormatTestTuple::getFieldByName( const UnicodeString &name) { CharString buffer; UErrorCode status = U_ZERO_ERROR; buffer.appendInvariantChars(name, status); if (U_FAILURE(status)) { return kNumberFormatTestTupleFieldCount; } int32_t result = -1; for (int32_t i = 0; i < UPRV_LENGTHOF(gFieldData); ++i) { if (uprv_strcmp(gFieldData[i].name, buffer.data()) == 0) { result = i; break; } } if (result == -1) { return kNumberFormatTestTupleFieldCount; } return (ENumberFormatTestTupleField) result; }
void DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status, UBool useLastResortData) { if (U_FAILURE(status)) { return; } *validLocale = *actualLocale = 0; currPattern = NULL; // First initialize all the symbols to the fallbacks for anything we can't find initialize(); // // Next get the numbering system for this locale and set zero digit // and the digit string based on the numbering system for the locale // LocalPointer<NumberingSystem> ns(NumberingSystem::createInstance(loc, status)); const char *nsName; if (U_SUCCESS(status) && ns->getRadix() == 10 && !ns->isAlgorithmic()) { nsName = ns->getName(); UnicodeString digitString(ns->getDescription()); int32_t digitIndex = 0; UChar32 digit = digitString.char32At(0); fSymbols[kZeroDigitSymbol].setTo(digit); for (int32_t i = kOneDigitSymbol; i <= kNineDigitSymbol; ++i) { digitIndex += U16_LENGTH(digit); digit = digitString.char32At(digitIndex); fSymbols[i].setTo(digit); } } else { nsName = gLatn; } // Open resource bundles const char* locStr = loc.getName(); LocalUResourceBundlePointer resource(ures_open(NULL, locStr, &status)); LocalUResourceBundlePointer numberElementsRes( ures_getByKeyWithFallback(resource.getAlias(), gNumberElements, NULL, &status)); if (U_FAILURE(status)) { if ( useLastResortData ) { status = U_USING_DEFAULT_WARNING; initialize(); } return; } // Set locale IDs // TODO: Is there a way to do this without depending on the resource bundle instance? U_LOCALE_BASED(locBased, *this); locBased.setLocaleIDs( ures_getLocaleByType( numberElementsRes.getAlias(), ULOC_VALID_LOCALE, &status), ures_getLocaleByType( numberElementsRes.getAlias(), ULOC_ACTUAL_LOCALE, &status)); // Now load the rest of the data from the data sink. // Start with loading this nsName if it is not Latin. DecFmtSymDataSink sink(*this); if (uprv_strcmp(nsName, gLatn) != 0) { CharString path; path.append(gNumberElements, status) .append('/', status) .append(nsName, status) .append('/', status) .append(gSymbols, status); ures_getAllItemsWithFallback(resource.getAlias(), path.data(), sink, status); // If no symbols exist for the given nsName and resource bundle, silently ignore // and fall back to Latin. if (status == U_MISSING_RESOURCE_ERROR) { status = U_ZERO_ERROR; } else if (U_FAILURE(status)) { return; } } // Continue with Latin if necessary. if (!sink.seenAll()) { ures_getAllItemsWithFallback(resource.getAlias(), gNumberElementsLatnSymbols, sink, status); if (U_FAILURE(status)) { return; } } // Let the monetary number separators equal the default number separators if necessary. sink.resolveMissingMonetarySeparators(fSymbols); // Obtain currency data from the currency API. This is strictly // for backward compatibility; we don't use DecimalFormatSymbols // for currency data anymore. UErrorCode internalStatus = U_ZERO_ERROR; // don't propagate failures out UChar curriso[4]; UnicodeString tempStr; ucurr_forLocale(locStr, curriso, 4, &internalStatus); uprv_getStaticCurrencyName(curriso, locStr, tempStr, internalStatus); if (U_SUCCESS(internalStatus)) { fSymbols[kIntlCurrencySymbol].setTo(curriso, -1); fSymbols[kCurrencySymbol] = tempStr; } /* else use the default values. */ //load the currency data UChar ucc[4]={0}; //Currency Codes are always 3 chars long int32_t uccLen = 4; const char* locName = loc.getName(); UErrorCode localStatus = U_ZERO_ERROR; uccLen = ucurr_forLocale(locName, ucc, uccLen, &localStatus); if(U_SUCCESS(localStatus) && uccLen > 0) { char cc[4]={0}; u_UCharsToChars(ucc, cc, uccLen); /* An explicit currency was requested */ LocalUResourceBundlePointer currencyResource(ures_open(U_ICUDATA_CURR, locStr, &localStatus)); LocalUResourceBundlePointer currency( ures_getByKeyWithFallback(currencyResource.getAlias(), "Currencies", NULL, &localStatus)); ures_getByKeyWithFallback(currency.getAlias(), cc, currency.getAlias(), &localStatus); if(U_SUCCESS(localStatus) && ures_getSize(currency.getAlias())>2) { // the length is 3 if more data is present ures_getByIndex(currency.getAlias(), 2, currency.getAlias(), &localStatus); int32_t currPatternLen = 0; currPattern = ures_getStringByIndex(currency.getAlias(), (int32_t)0, &currPatternLen, &localStatus); UnicodeString decimalSep = ures_getUnicodeStringByIndex(currency.getAlias(), (int32_t)1, &localStatus); UnicodeString groupingSep = ures_getUnicodeStringByIndex(currency.getAlias(), (int32_t)2, &localStatus); if(U_SUCCESS(localStatus)){ fSymbols[kMonetaryGroupingSeparatorSymbol] = groupingSep; fSymbols[kMonetarySeparatorSymbol] = decimalSep; //pattern.setTo(TRUE, currPattern, currPatternLen); status = localStatus; } } /* else An explicit currency was requested and is unknown or locale data is malformed. */ /* ucurr_* API will get the correct value later on. */ } // else ignore the error if no currency // Currency Spacing. localStatus = U_ZERO_ERROR; LocalUResourceBundlePointer currencyResource(ures_open(U_ICUDATA_CURR, locStr, &localStatus)); LocalUResourceBundlePointer currencySpcRes( ures_getByKeyWithFallback(currencyResource.getAlias(), gCurrencySpacingTag, NULL, &localStatus)); if (localStatus == U_USING_FALLBACK_WARNING || U_SUCCESS(localStatus)) { const char* keywords[UNUM_CURRENCY_SPACING_COUNT] = { gCurrencyMatchTag, gCurrencySudMatchTag, gCurrencyInsertBtnTag }; localStatus = U_ZERO_ERROR; LocalUResourceBundlePointer dataRes( ures_getByKeyWithFallback(currencySpcRes.getAlias(), gBeforeCurrencyTag, NULL, &localStatus)); if (localStatus == U_USING_FALLBACK_WARNING || U_SUCCESS(localStatus)) { localStatus = U_ZERO_ERROR; for (int32_t i = 0; i < UNUM_CURRENCY_SPACING_COUNT; i++) { currencySpcBeforeSym[i] = ures_getUnicodeStringByKey(dataRes.getAlias(), keywords[i], &localStatus); } } dataRes.adoptInstead( ures_getByKeyWithFallback(currencySpcRes.getAlias(), gAfterCurrencyTag, NULL, &localStatus)); if (localStatus == U_USING_FALLBACK_WARNING || U_SUCCESS(localStatus)) { localStatus = U_ZERO_ERROR; for (int32_t i = 0; i < UNUM_CURRENCY_SPACING_COUNT; i++) { currencySpcAfterSym[i] = ures_getUnicodeStringByKey(dataRes.getAlias(), keywords[i], &localStatus); } } } }
int main(int argc, char* argv[]) { UErrorCode status = U_ZERO_ERROR; const char *arg = NULL; const char *outputDir = NULL; /* NULL = no output directory, use current */ const char *inputDir = NULL; const char *encoding = ""; int i; UBool illegalArg = FALSE; U_MAIN_INIT_ARGS(argc, argv); options[JAVA_PACKAGE].value = "com.ibm.icu.impl.data"; options[BUNDLE_NAME].value = "LocaleElements"; argc = u_parseArgs(argc, argv, UPRV_LENGTHOF(options), options); /* error handling, printing usage message */ if(argc<0) { fprintf(stderr, "%s: error in command line argument \"%s\"\n", argv[0], argv[-argc]); illegalArg = TRUE; } else if(argc<2) { illegalArg = TRUE; } if(options[WRITE_POOL_BUNDLE].doesOccur && options[USE_POOL_BUNDLE].doesOccur) { fprintf(stderr, "%s: cannot combine --writePoolBundle and --usePoolBundle\n", argv[0]); illegalArg = TRUE; } if(options[FORMAT_VERSION].doesOccur) { const char *s = options[FORMAT_VERSION].value; if(uprv_strlen(s) != 1 || (s[0] < '1' && '3' < s[0])) { fprintf(stderr, "%s: unsupported --formatVersion %s\n", argv[0], s); illegalArg = TRUE; } else if(s[0] == '1' && (options[WRITE_POOL_BUNDLE].doesOccur || options[USE_POOL_BUNDLE].doesOccur) ) { fprintf(stderr, "%s: cannot combine --formatVersion 1 with --writePoolBundle or --usePoolBundle\n", argv[0]); illegalArg = TRUE; } else { setFormatVersion(s[0] - '0'); } } if((options[JAVA_PACKAGE].doesOccur || options[BUNDLE_NAME].doesOccur) && !options[WRITE_JAVA].doesOccur) { fprintf(stderr, "%s error: command line argument --java-package or --bundle-name " "without --write-java\n", argv[0]); illegalArg = TRUE; } if(options[VERSION].doesOccur) { fprintf(stderr, "%s version %s (ICU version %s).\n" "%s\n", argv[0], GENRB_VERSION, U_ICU_VERSION, U_COPYRIGHT_STRING); if(!illegalArg) { return U_ZERO_ERROR; } } if(illegalArg || options[HELP1].doesOccur || options[HELP2].doesOccur) { /* * Broken into chunks because the C89 standard says the minimum * required supported string length is 509 bytes. */ fprintf(stderr, "Usage: %s [OPTIONS] [FILES]\n" "\tReads the list of resource bundle source files and creates\n" "\tbinary version of resource bundles (.res files)\n", argv[0]); fprintf(stderr, "Options:\n" "\t-h or -? or --help this usage text\n" "\t-q or --quiet do not display warnings\n" "\t-v or --verbose print extra information when processing files\n" "\t-V or --version prints out version number and exits\n" "\t-c or --copyright include copyright notice\n"); fprintf(stderr, "\t-e or --encoding encoding of source files\n" "\t-d of --destdir destination directory, followed by the path, defaults to %s\n" "\t-s or --sourcedir source directory for files followed by path, defaults to %s\n" "\t-i or --icudatadir directory for locating any needed intermediate data files,\n" "\t followed by path, defaults to %s\n", u_getDataDirectory(), u_getDataDirectory(), u_getDataDirectory()); fprintf(stderr, "\t-j or --write-java write a Java ListResourceBundle for ICU4J, followed by optional encoding\n" "\t defaults to ASCII and \\uXXXX format.\n" "\t --java-package For --write-java: package name for writing the ListResourceBundle,\n" "\t defaults to com.ibm.icu.impl.data\n"); fprintf(stderr, "\t-b or --bundle-name For --write-java: root resource bundle name for writing the ListResourceBundle,\n" "\t defaults to LocaleElements\n" "\t-x or --write-xliff write an XLIFF file for the resource bundle. Followed by\n" "\t an optional output file name.\n" "\t-k or --strict use pedantic parsing of syntax\n" /*added by Jing*/ "\t-l or --language for XLIFF: language code compliant with BCP 47.\n"); fprintf(stderr, "\t-C or --noBinaryCollation do not generate binary collation image;\n" "\t makes .res file smaller but collator instantiation much slower;\n" "\t maintains ability to get tailoring rules\n" "\t-R or --omitCollationRules do not include collation (tailoring) rules;\n" "\t makes .res file smaller and maintains collator instantiation speed\n" "\t but tailoring rules will not be available (they are rarely used)\n"); fprintf(stderr, "\t --formatVersion write a .res file compatible with the requested formatVersion (single digit);\n" "\t for example, --formatVersion 1\n"); fprintf(stderr, "\t --writePoolBundle write a pool.res file with all of the keys of all input bundles\n" "\t --usePoolBundle [path-to-pool.res] point to keys from the pool.res keys pool bundle if they are available there;\n" "\t makes .res files smaller but dependent on the pool bundle\n" "\t (--writePoolBundle and --usePoolBundle cannot be combined)\n"); return illegalArg ? U_ILLEGAL_ARGUMENT_ERROR : U_ZERO_ERROR; } if(options[VERBOSE].doesOccur) { setVerbose(TRUE); } if(options[QUIET].doesOccur) { setShowWarning(FALSE); } if(options[STRICT].doesOccur) { setStrict(TRUE); } if(options[COPYRIGHT].doesOccur){ setIncludeCopyright(TRUE); } if(options[SOURCEDIR].doesOccur) { inputDir = options[SOURCEDIR].value; } if(options[DESTDIR].doesOccur) { outputDir = options[DESTDIR].value; } if(options[ENCODING].doesOccur) { encoding = options[ENCODING].value; } if(options[ICUDATADIR].doesOccur) { u_setDataDirectory(options[ICUDATADIR].value); } /* Initialize ICU */ u_init(&status); if (U_FAILURE(status) && status != U_FILE_ACCESS_ERROR) { /* Note: u_init() will try to open ICU property data. * failures here are expected when building ICU from scratch. * ignore them. */ fprintf(stderr, "%s: can not initialize ICU. status = %s\n", argv[0], u_errorName(status)); exit(1); } status = U_ZERO_ERROR; if(options[WRITE_JAVA].doesOccur) { write_java = TRUE; outputEnc = options[WRITE_JAVA].value; } if(options[WRITE_XLIFF].doesOccur) { write_xliff = TRUE; if(options[WRITE_XLIFF].value != NULL){ xliffOutputFileName = options[WRITE_XLIFF].value; } } initParser(); /*added by Jing*/ if(options[LANGUAGE].doesOccur) { language = options[LANGUAGE].value; } LocalPointer<SRBRoot> newPoolBundle; if(options[WRITE_POOL_BUNDLE].doesOccur) { newPoolBundle.adoptInsteadAndCheckErrorCode(new SRBRoot(NULL, TRUE, status), status); if(U_FAILURE(status)) { fprintf(stderr, "unable to create an empty bundle for the pool keys: %s\n", u_errorName(status)); return status; } else { const char *poolResName = "pool.res"; char *nameWithoutSuffix = static_cast<char *>(uprv_malloc(uprv_strlen(poolResName) + 1)); if (nameWithoutSuffix == NULL) { fprintf(stderr, "out of memory error\n"); return U_MEMORY_ALLOCATION_ERROR; } uprv_strcpy(nameWithoutSuffix, poolResName); *uprv_strrchr(nameWithoutSuffix, '.') = 0; newPoolBundle->fLocale = nameWithoutSuffix; } } if(options[USE_POOL_BUNDLE].doesOccur) { const char *poolResName = "pool.res"; FileStream *poolFile; int32_t poolFileSize; int32_t indexLength; /* * TODO: Consolidate inputDir/filename handling from main() and processFile() * into a common function, and use it here as well. * Try to create toolutil functions for dealing with dir/filenames and * loading ICU data files without udata_open(). * Share code with icupkg? * Also, make_res_filename() seems to be unused. Review and remove. */ CharString poolFileName; if (options[USE_POOL_BUNDLE].value!=NULL) { poolFileName.append(options[USE_POOL_BUNDLE].value, status); } else if (inputDir) { poolFileName.append(inputDir, status); } poolFileName.appendPathPart(poolResName, status); if (U_FAILURE(status)) { return status; } poolFile = T_FileStream_open(poolFileName.data(), "rb"); if (poolFile == NULL) { fprintf(stderr, "unable to open pool bundle file %s\n", poolFileName.data()); return 1; } poolFileSize = T_FileStream_size(poolFile); if (poolFileSize < 32) { fprintf(stderr, "the pool bundle file %s is too small\n", poolFileName.data()); return 1; } poolBundle.fBytes = new uint8_t[(poolFileSize + 15) & ~15]; if (poolFileSize > 0 && poolBundle.fBytes == NULL) { fprintf(stderr, "unable to allocate memory for the pool bundle file %s\n", poolFileName.data()); return U_MEMORY_ALLOCATION_ERROR; } UDataSwapper *ds; const DataHeader *header; int32_t bytesRead = T_FileStream_read(poolFile, poolBundle.fBytes, poolFileSize); if (bytesRead != poolFileSize) { fprintf(stderr, "unable to read the pool bundle file %s\n", poolFileName.data()); return 1; } /* * Swap the pool bundle so that a single checked-in file can be used. * The swapper functions also test that the data looks like * a well-formed .res file. */ ds = udata_openSwapperForInputData(poolBundle.fBytes, bytesRead, U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, &status); if (U_FAILURE(status)) { fprintf(stderr, "udata_openSwapperForInputData(pool bundle %s) failed: %s\n", poolFileName.data(), u_errorName(status)); return status; } ures_swap(ds, poolBundle.fBytes, bytesRead, poolBundle.fBytes, &status); udata_closeSwapper(ds); if (U_FAILURE(status)) { fprintf(stderr, "ures_swap(pool bundle %s) failed: %s\n", poolFileName.data(), u_errorName(status)); return status; } header = (const DataHeader *)poolBundle.fBytes; if (header->info.formatVersion[0] < 2) { fprintf(stderr, "invalid format of pool bundle file %s\n", poolFileName.data()); return U_INVALID_FORMAT_ERROR; } const int32_t *pRoot = (const int32_t *)( (const char *)header + header->dataHeader.headerSize); poolBundle.fIndexes = pRoot + 1; indexLength = poolBundle.fIndexes[URES_INDEX_LENGTH] & 0xff; if (indexLength <= URES_INDEX_POOL_CHECKSUM) { fprintf(stderr, "insufficient indexes[] in pool bundle file %s\n", poolFileName.data()); return U_INVALID_FORMAT_ERROR; } int32_t keysBottom = 1 + indexLength; int32_t keysTop = poolBundle.fIndexes[URES_INDEX_KEYS_TOP]; poolBundle.fKeys = (const char *)(pRoot + keysBottom); poolBundle.fKeysLength = (keysTop - keysBottom) * 4; poolBundle.fChecksum = poolBundle.fIndexes[URES_INDEX_POOL_CHECKSUM]; for (i = 0; i < poolBundle.fKeysLength; ++i) { if (poolBundle.fKeys[i] == 0) { ++poolBundle.fKeysCount; } } // 16BitUnits[] begins with strings-v2. // The strings-v2 may optionally be terminated by what looks like // an explicit string length that exceeds the number of remaining 16-bit units. int32_t stringUnitsLength = (poolBundle.fIndexes[URES_INDEX_16BIT_TOP] - keysTop) * 2; if (stringUnitsLength >= 2 && getFormatVersion() >= 3) { poolBundle.fStrings = new PseudoListResource(NULL, status); if (poolBundle.fStrings == NULL) { fprintf(stderr, "unable to allocate memory for the pool bundle strings %s\n", poolFileName.data()); return U_MEMORY_ALLOCATION_ERROR; } // The PseudoListResource constructor call did not allocate further memory. assert(U_SUCCESS(status)); const UChar *p = (const UChar *)(pRoot + keysTop); int32_t remaining = stringUnitsLength; do { int32_t first = *p; int8_t numCharsForLength; int32_t length; if (!U16_IS_TRAIL(first)) { // NUL-terminated numCharsForLength = 0; for (length = 0; length < remaining && p[length] != 0; ++length) {} } else if (first < 0xdfef) { numCharsForLength = 1; length = first & 0x3ff; } else if (first < 0xdfff && remaining >= 2) { numCharsForLength = 2; length = ((first - 0xdfef) << 16) | p[1]; } else if (first == 0xdfff && remaining >= 3) { numCharsForLength = 3; length = ((int32_t)p[1] << 16) | p[2]; } else { break; // overrun } // Check for overrun before changing remaining, // so that it is always accurate after the loop body. if ((numCharsForLength + length) >= remaining || p[numCharsForLength + length] != 0) { break; // overrun or explicitly terminated } int32_t poolStringIndex = stringUnitsLength - remaining; // Maximum pool string index when suffix-sharing the last character. int32_t maxStringIndex = poolStringIndex + numCharsForLength + length - 1; if (maxStringIndex >= RES_MAX_OFFSET) { // pool string index overrun break; } p += numCharsForLength; remaining -= numCharsForLength; if (length != 0) { StringResource *sr = new StringResource(poolStringIndex, numCharsForLength, p, length, status); if (sr == NULL) { fprintf(stderr, "unable to allocate memory for a pool bundle string %s\n", poolFileName.data()); return U_MEMORY_ALLOCATION_ERROR; } poolBundle.fStrings->add(sr); poolBundle.fStringIndexLimit = maxStringIndex + 1; // The StringResource constructor did not allocate further memory. assert(U_SUCCESS(status)); } p += length + 1; remaining -= length + 1; } while (remaining > 0); if (poolBundle.fStrings->fCount == 0) { delete poolBundle.fStrings; poolBundle.fStrings = NULL; } } T_FileStream_close(poolFile); setUsePoolBundle(TRUE); if (isVerbose() && poolBundle.fStrings != NULL) { printf("number of shared strings: %d\n", (int)poolBundle.fStrings->fCount); int32_t length = poolBundle.fStringIndexLimit + 1; // incl. last NUL printf("16-bit units for strings: %6d = %6d bytes\n", (int)length, (int)length * 2); } } if(!options[FORMAT_VERSION].doesOccur && getFormatVersion() == 3 && poolBundle.fStrings == NULL && !options[WRITE_POOL_BUNDLE].doesOccur) { // If we just default to formatVersion 3 // but there are no pool bundle strings to share // and we do not write a pool bundle, // then write formatVersion 2 which is just as good. setFormatVersion(2); } if(options[INCLUDE_UNIHAN_COLL].doesOccur) { puts("genrb option --includeUnihanColl ignored: \n" "CLDR 26/ICU 54 unihan data is small, except\n" "the ucadata-unihan.icu version of the collation root data\n" "is about 300kB larger than the ucadata-implicithan.icu version."); } if((argc-1)!=1) { printf("genrb number of files: %d\n", argc - 1); } /* generate the binary files */ for(i = 1; i < argc; ++i) { status = U_ZERO_ERROR; arg = getLongPathname(argv[i]); CharString theCurrentFileName; if (inputDir) { theCurrentFileName.append(inputDir, status); } theCurrentFileName.appendPathPart(arg, status); if (U_FAILURE(status)) { break; } gCurrentFileName = theCurrentFileName.data(); if (isVerbose()) { printf("Processing file \"%s\"\n", theCurrentFileName.data()); } processFile(arg, encoding, inputDir, outputDir, NULL, newPoolBundle.getAlias(), options[NO_BINARY_COLLATION].doesOccur, status); } poolBundle.close(); if(U_SUCCESS(status) && options[WRITE_POOL_BUNDLE].doesOccur) { char outputFileName[256]; newPoolBundle->write(outputDir, NULL, outputFileName, sizeof(outputFileName), status); if(U_FAILURE(status)) { fprintf(stderr, "unable to write the pool bundle: %s\n", u_errorName(status)); } } u_cleanup(); /* Dont return warnings as a failure */ if (U_SUCCESS(status)) { return 0; } return status; }
U_CAPI void U_EXPORT2 uplug_init(UErrorCode *status) { #if !U_ENABLE_DYLOAD (void)status; /* unused */ #elif !UCONFIG_NO_FILE_IO CharString plugin_dir; const char *env = getenv("ICU_PLUGINS"); if(U_FAILURE(*status)) return; if(env != NULL) { plugin_dir.append(env, -1, *status); } if(U_FAILURE(*status)) return; #if defined(DEFAULT_ICU_PLUGINS) if(plugin_dir.isEmpty()) { plugin_dir.append(DEFAULT_ICU_PLUGINS, -1, *status); } #endif #if UPLUG_TRACE DBG((stderr, "ICU_PLUGINS=%s\n", plugin_dir.data())); #endif if(!plugin_dir.isEmpty()) { FILE *f; CharString pluginFile; #ifdef OS390BATCH /* There are potentially a lot of ways to implement a plugin directory on OS390/zOS */ /* Keeping in mind that unauthorized file access is logged, monitored, and enforced */ /* I've chosen to open a DDNAME if BATCH and leave it alone for (presumably) UNIX */ /* System Services. Alternative techniques might be allocating a member in */ /* SYS1.PARMLIB or setting an environment variable "ICU_PLUGIN_PATH" (?). The */ /* DDNAME can be connected to a file in the HFS if need be. */ pluginFile.append("//DD:ICUPLUG", -1, *status); /* JAM 20 Oct 2011 */ #else pluginFile.append(plugin_dir, *status); pluginFile.append(U_FILE_SEP_STRING, -1, *status); pluginFile.append("icuplugins", -1, *status); pluginFile.append(U_ICU_VERSION_SHORT, -1, *status); pluginFile.append(".txt", -1, *status); #endif #if UPLUG_TRACE DBG((stderr, "status=%s\n", u_errorName(*status))); #endif if(U_FAILURE(*status)) { return; } if((size_t)pluginFile.length() > (sizeof(plugin_file)-1)) { *status = U_BUFFER_OVERFLOW_ERROR; #if UPLUG_TRACE DBG((stderr, "status=%s\n", u_errorName(*status))); #endif return; } /* plugin_file is not used for processing - it is only used so that uplug_getPluginFile() works (i.e. icuinfo) */ uprv_strncpy(plugin_file, pluginFile.data(), sizeof(plugin_file)); #if UPLUG_TRACE DBG((stderr, "pluginfile= %s len %d/%d\n", plugin_file, (int)strlen(plugin_file), (int)sizeof(plugin_file))); #endif #ifdef __MVS__ if (iscics()) /* 12 Nov 2011 JAM */ { f = NULL; } else #endif { f = fopen(pluginFile.data(), "r"); } if(f != NULL) { char linebuf[1024]; char *p, *libName=NULL, *symName=NULL, *config=NULL; int32_t line = 0; while(fgets(linebuf,1023,f)) { line++; if(!*linebuf || *linebuf=='#') { continue; } else { p = linebuf; while(*p&&isspace((int)*p)) p++; if(!*p || *p=='#') continue; libName = p; while(*p&&!isspace((int)*p)) { p++; } if(!*p || *p=='#') continue; /* no tab after libname */ *p=0; /* end of libname */ p++; while(*p&&isspace((int)*p)) { p++; } if(!*p||*p=='#') continue; /* no symname after libname +tab */ symName = p; while(*p&&!isspace((int)*p)) { p++; } if(*p) { /* has config */ *p=0; ++p; while(*p&&isspace((int)*p)) { p++; } if(*p) { config = p; } } /* chop whitespace at the end of the config */ if(config!=NULL&&*config!=0) { p = config+strlen(config); while(p>config&&isspace((int)*(--p))) { *p=0; } } /* OK, we're good. */ { UErrorCode subStatus = U_ZERO_ERROR; UPlugData *plug = uplug_initPlugFromLibrary(libName, symName, config, &subStatus); if(U_FAILURE(subStatus) && U_SUCCESS(*status)) { *status = subStatus; } #if UPLUG_TRACE DBG((stderr, "PLUGIN libName=[%s], sym=[%s], config=[%s]\n", libName, symName, config)); DBG((stderr, " -> %p, %s\n", (void*)plug, u_errorName(subStatus))); #else (void)plug; /* unused */ #endif } } } fclose(f); } else { #if UPLUG_TRACE DBG((stderr, "Can't open plugin file %s\n", plugin_file)); #endif } } uplug_loadWaitingPlugs(status); #endif /* U_ENABLE_DYLOAD */ ucln_registerCleanup(UCLN_UPLUG, uplug_cleanup); }
// Returns TRUE for "ok to continue parsing fields". UBool PreparsedUCD::parseProperty(UniProps &props, const char *field, UnicodeSet &newValues, UErrorCode &errorCode) { CharString pBuffer; const char *p=field; const char *v=strchr(p, '='); int binaryValue; if(*p=='-') { if(v!=NULL) { fprintf(stderr, "error in preparsed UCD: mix of binary-property-no and " "enum-property syntax '%s' on line %ld\n", field, (long)lineNumber); errorCode=U_PARSE_ERROR; return FALSE; } binaryValue=0; ++p; } else if(v==NULL) { binaryValue=1; } else { binaryValue=-1; // Copy out the property name rather than modifying the field (writing a NUL). pBuffer.append(p, (int32_t)(v-p), errorCode); p=pBuffer.data(); ++v; } int32_t prop=pnames->getPropertyEnum(p); if(prop<0) { for(int32_t i=0;; ++i) { if(i==UPRV_LENGTHOF(ppucdProperties)) { // Ignore unknown property names. return TRUE; } if(0==uprv_stricmp(p, ppucdProperties[i].name)) { prop=ppucdProperties[i].prop; U_ASSERT(prop>=0); break; } } } if(prop<UCHAR_BINARY_LIMIT) { if(binaryValue>=0) { props.binProps[prop]=(UBool)binaryValue; } else { // No binary value for a binary property. fprintf(stderr, "error in preparsed UCD: enum-property syntax '%s' " "for binary property on line %ld\n", field, (long)lineNumber); errorCode=U_PARSE_ERROR; } } else if(binaryValue>=0) { // Binary value for a non-binary property. fprintf(stderr, "error in preparsed UCD: binary-property syntax '%s' " "for non-binary property on line %ld\n", field, (long)lineNumber); errorCode=U_PARSE_ERROR; } else if (prop < UCHAR_INT_START) { fprintf(stderr, "error in preparsed UCD: prop value is invalid: '%d' for line %ld\n", prop, (long)lineNumber); errorCode=U_PARSE_ERROR; } else if(prop<UCHAR_INT_LIMIT) { int32_t value=pnames->getPropertyValueEnum(prop, v); if(value==UCHAR_INVALID_CODE && prop==UCHAR_CANONICAL_COMBINING_CLASS) { // TODO: Make getPropertyValueEnum(UCHAR_CANONICAL_COMBINING_CLASS, v) work. char *end; unsigned long ccc=uprv_strtoul(v, &end, 10); if(v<end && *end==0 && ccc<=254) { value=(int32_t)ccc; } } if(value==UCHAR_INVALID_CODE) { fprintf(stderr, "error in preparsed UCD: '%s' is not a valid value on line %ld\n", field, (long)lineNumber); errorCode=U_PARSE_ERROR; } else { props.intProps[prop-UCHAR_INT_START]=value; } } else if(*v=='<') { // Do not parse default values like <code point>, just set null values. switch(prop) { case UCHAR_BIDI_MIRRORING_GLYPH: props.bmg=U_SENTINEL; break; case UCHAR_BIDI_PAIRED_BRACKET: props.bpb=U_SENTINEL; break; case UCHAR_SIMPLE_CASE_FOLDING: props.scf=U_SENTINEL; break; case UCHAR_SIMPLE_LOWERCASE_MAPPING: props.slc=U_SENTINEL; break; case UCHAR_SIMPLE_TITLECASE_MAPPING: props.stc=U_SENTINEL; break; case UCHAR_SIMPLE_UPPERCASE_MAPPING: props.suc=U_SENTINEL; break; case UCHAR_CASE_FOLDING: props.cf.remove(); break; case UCHAR_LOWERCASE_MAPPING: props.lc.remove(); break; case UCHAR_TITLECASE_MAPPING: props.tc.remove(); break; case UCHAR_UPPERCASE_MAPPING: props.uc.remove(); break; case UCHAR_SCRIPT_EXTENSIONS: props.scx.clear(); break; default: fprintf(stderr, "error in preparsed UCD: '%s' is not a valid default value on line %ld\n", field, (long)lineNumber); errorCode=U_PARSE_ERROR; } } else { char c; switch(prop) { case UCHAR_NUMERIC_VALUE: props.numericValue=v; c=*v; if('0'<=c && c<='9' && v[1]==0) { props.digitValue=c-'0'; } else { props.digitValue=-1; } break; case UCHAR_NAME: props.name=v; break; case UCHAR_AGE: u_versionFromString(props.age, v); // Writes 0.0.0.0 if v is not numeric. break; case UCHAR_BIDI_MIRRORING_GLYPH: props.bmg=parseCodePoint(v, errorCode); break; case UCHAR_BIDI_PAIRED_BRACKET: props.bpb=parseCodePoint(v, errorCode); break; case UCHAR_SIMPLE_CASE_FOLDING: props.scf=parseCodePoint(v, errorCode); break; case UCHAR_SIMPLE_LOWERCASE_MAPPING: props.slc=parseCodePoint(v, errorCode); break; case UCHAR_SIMPLE_TITLECASE_MAPPING: props.stc=parseCodePoint(v, errorCode); break; case UCHAR_SIMPLE_UPPERCASE_MAPPING: props.suc=parseCodePoint(v, errorCode); break; case UCHAR_CASE_FOLDING: parseString(v, props.cf, errorCode); break; case UCHAR_LOWERCASE_MAPPING: parseString(v, props.lc, errorCode); break; case UCHAR_TITLECASE_MAPPING: parseString(v, props.tc, errorCode); break; case UCHAR_UPPERCASE_MAPPING: parseString(v, props.uc, errorCode); break; case PPUCD_NAME_ALIAS: props.nameAlias=v; break; case PPUCD_CONDITIONAL_CASE_MAPPINGS: case PPUCD_TURKIC_CASE_FOLDING: // No need to parse their values: They are hardcoded in the runtime library. break; case UCHAR_SCRIPT_EXTENSIONS: parseScriptExtensions(v, props.scx, errorCode); break; default: // Ignore unhandled properties. return TRUE; } } if(U_SUCCESS(errorCode)) { newValues.add((UChar32)prop); return TRUE; } else { return FALSE; } }
// Helpers. static int32_t parseSetNum(const UnicodeString &setNumStr, UErrorCode &errorCode) { CharString cs; cs.appendInvariantChars(setNumStr, errorCode); return parseSetNum(cs.data(), errorCode); }
const Hashtable * LocaleUtility::getAvailableLocaleNames(const UnicodeString & bundleID) { // LocaleUtility_cache is a hash-of-hashes. The top-level keys // are path strings ('bundleID') passed to // ures_openAvailableLocales. The top-level values are // second-level hashes. The second-level keys are result strings // from ures_openAvailableLocales. The second-level values are // garbage ((void*)1 or other random pointer). UErrorCode status = U_ZERO_ERROR; Hashtable * cache; umtx_lock(NULL); cache = LocaleUtility_cache; umtx_unlock(NULL); if (cache == NULL) { cache = new Hashtable(status); if (cache == NULL || U_FAILURE(status)) { return NULL; // catastrophic failure; e.g. out of memory } cache->setValueDeleter(uhash_deleteHashtable); Hashtable * h; // set this to final LocaleUtility_cache value umtx_lock(NULL); h = LocaleUtility_cache; if (h == NULL) { LocaleUtility_cache = h = cache; cache = NULL; ucln_common_registerCleanup(UCLN_COMMON_SERVICE, service_cleanup); } umtx_unlock(NULL); if (cache != NULL) { delete cache; } cache = h; } U_ASSERT(cache != NULL); Hashtable * htp; umtx_lock(NULL); htp = (Hashtable *) cache->get(bundleID); umtx_unlock(NULL); if (htp == NULL) { htp = new Hashtable(status); if (htp && U_SUCCESS(status)) { CharString cbundleID; cbundleID.appendInvariantChars(bundleID, status); const char * path = cbundleID.isEmpty() ? NULL : cbundleID.data(); UEnumeration * uenum = ures_openAvailableLocales(path, &status); for (;;) { const UChar * id = uenum_unext(uenum, NULL, &status); if (id == NULL) { break; } htp->put(UnicodeString(id), (void *)htp, status); } uenum_close(uenum); if (U_FAILURE(status)) { delete htp; return NULL; } umtx_lock(NULL); cache->put(bundleID, (void *)htp, status); umtx_unlock(NULL); } } return htp; }
UnicodeString &QuantityFormatter::format( const Formattable& quantity, const NumberFormat &fmt, const PluralRules &rules, UnicodeString &appendTo, FieldPosition &pos, UErrorCode &status) const { if (U_FAILURE(status)) { return appendTo; } UnicodeString count; const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt); if (decFmt != NULL) { FixedDecimal fd = decFmt->getFixedDecimal(quantity, status); if (U_FAILURE(status)) { return appendTo; } count = rules.select(fd); } else { if (quantity.getType() == Formattable::kDouble) { count = rules.select(quantity.getDouble()); } else if (quantity.getType() == Formattable::kLong) { count = rules.select(quantity.getLong()); } else if (quantity.getType() == Formattable::kInt64) { count = rules.select((double) quantity.getInt64()); } else { status = U_ILLEGAL_ARGUMENT_ERROR; return appendTo; } } CharString buffer; buffer.appendInvariantChars(count, status); if (U_FAILURE(status)) { return appendTo; } int32_t pluralIndex = getPluralIndex(buffer.data()); if (pluralIndex == -1) { pluralIndex = 0; } const SimplePatternFormatter *pattern = formatters[pluralIndex]; if (pattern == NULL) { pattern = formatters[0]; } if (pattern == NULL) { status = U_INVALID_STATE_ERROR; return appendTo; } UnicodeString formattedNumber; FieldPosition fpos(pos.getField()); fmt.format(quantity, formattedNumber, fpos, status); const UnicodeString *params[1] = {&formattedNumber}; int32_t offsets[1]; pattern->format(params, LENGTHOF(params), appendTo, offsets, LENGTHOF(offsets), status); if (offsets[0] != -1) { if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) { pos.setBeginIndex(fpos.getBeginIndex() + offsets[0]); pos.setEndIndex(fpos.getEndIndex() + offsets[0]); } } return appendTo; }
NumberFormat* NumberFormat::makeInstance(const Locale& desiredLocale, UNumberFormatStyle style, UBool mustBeDecimalFormat, UErrorCode& status) { if (U_FAILURE(status)) return NULL; if (style < 0 || style >= UNUM_FORMAT_STYLE_COUNT) { status = U_ILLEGAL_ARGUMENT_ERROR; return NULL; } // Some styles are not supported. This is a result of merging // the @draft ICU 4.2 NumberFormat::EStyles into the long-existing UNumberFormatStyle. // Ticket #8503 is for reviewing/fixing/merging the two relevant implementations: // this one and unum_open(). // The UNUM_PATTERN_ styles are not supported here // because this method does not take a pattern string. if (!isStyleSupported(style)) { status = U_UNSUPPORTED_ERROR; return NULL; } #if U_PLATFORM_USES_ONLY_WIN32_API if (!mustBeDecimalFormat) { char buffer[8]; int32_t count = desiredLocale.getKeywordValue("compat", buffer, sizeof(buffer), status); // if the locale has "@compat=host", create a host-specific NumberFormat if (U_SUCCESS(status) && count > 0 && uprv_strcmp(buffer, "host") == 0) { Win32NumberFormat *f = NULL; UBool curr = TRUE; switch (style) { case UNUM_DECIMAL: curr = FALSE; // fall-through case UNUM_CURRENCY: case UNUM_CURRENCY_ISO: // do not support plural formatting here case UNUM_CURRENCY_PLURAL: f = new Win32NumberFormat(desiredLocale, curr, status); if (U_SUCCESS(status)) { return f; } delete f; break; default: break; } } } #endif // Use numbering system cache hashtable umtx_initOnce(gNSCacheInitOnce, &nscacheInit); // Get cached numbering system LocalPointer<NumberingSystem> ownedNs; NumberingSystem *ns = NULL; if (NumberingSystem_cache != NULL) { // TODO: Bad hash key usage, see ticket #8504. int32_t hashKey = desiredLocale.hashCode(); Mutex lock(&nscacheMutex); ns = (NumberingSystem *)uhash_iget(NumberingSystem_cache, hashKey); if (ns == NULL) { ns = NumberingSystem::createInstance(desiredLocale,status); uhash_iput(NumberingSystem_cache, hashKey, (void*)ns, &status); } } else { ownedNs.adoptInstead(NumberingSystem::createInstance(desiredLocale,status)); ns = ownedNs.getAlias(); } // check results of getting a numbering system if (U_FAILURE(status)) { return NULL; } if (mustBeDecimalFormat && ns->isAlgorithmic()) { status = U_UNSUPPORTED_ERROR; return NULL; } LocalPointer<DecimalFormatSymbols> symbolsToAdopt; UnicodeString pattern; LocalUResourceBundlePointer ownedResource(ures_open(NULL, desiredLocale.getName(), &status)); if (U_FAILURE(status)) { // We don't appear to have resource data available -- use the last-resort data status = U_USING_FALLBACK_WARNING; // When the data is unavailable, and locale isn't passed in, last resort data is used. symbolsToAdopt.adoptInstead(new DecimalFormatSymbols(status)); if (symbolsToAdopt.isNull()) { status = U_MEMORY_ALLOCATION_ERROR; return NULL; } // Creates a DecimalFormat instance with the last resort number patterns. pattern.setTo(TRUE, gLastResortNumberPatterns[style], -1); } else { // Loads the decimal symbols of the desired locale. symbolsToAdopt.adoptInstead(new DecimalFormatSymbols(desiredLocale, status)); if (symbolsToAdopt.isNull()) { status = U_MEMORY_ALLOCATION_ERROR; return NULL; } UResourceBundle *resource = ownedResource.orphan(); UResourceBundle *numElements = ures_getByKeyWithFallback(resource, gNumberElements, NULL, &status); resource = ures_getByKeyWithFallback(numElements, ns->getName(), resource, &status); resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status); ownedResource.adoptInstead(resource); int32_t patLen = 0; const UChar *patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status); // Didn't find a pattern specific to the numbering system, so fall back to "latn" if ( status == U_MISSING_RESOURCE_ERROR && uprv_strcmp(gLatn,ns->getName())) { status = U_ZERO_ERROR; resource = ures_getByKeyWithFallback(numElements, gLatn, resource, &status); resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status); patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status); } ures_close(numElements); // Creates the specified decimal format style of the desired locale. pattern.setTo(TRUE, patResStr, patLen); } if (U_FAILURE(status)) { return NULL; } if(style==UNUM_CURRENCY || style == UNUM_CURRENCY_ISO){ const UChar* currPattern = symbolsToAdopt->getCurrencyPattern(); if(currPattern!=NULL){ pattern.setTo(currPattern, u_strlen(currPattern)); } } NumberFormat *f; if (ns->isAlgorithmic()) { UnicodeString nsDesc; UnicodeString nsRuleSetGroup; UnicodeString nsRuleSetName; Locale nsLoc; URBNFRuleSetTag desiredRulesType = URBNF_NUMBERING_SYSTEM; nsDesc.setTo(ns->getDescription()); int32_t firstSlash = nsDesc.indexOf(gSlash); int32_t lastSlash = nsDesc.lastIndexOf(gSlash); if ( lastSlash > firstSlash ) { CharString nsLocID; nsLocID.appendInvariantChars(nsDesc.tempSubString(0, firstSlash), status); nsRuleSetGroup.setTo(nsDesc,firstSlash+1,lastSlash-firstSlash-1); nsRuleSetName.setTo(nsDesc,lastSlash+1); nsLoc = Locale::createFromName(nsLocID.data()); UnicodeString SpelloutRules = UNICODE_STRING_SIMPLE("SpelloutRules"); if ( nsRuleSetGroup.compare(SpelloutRules) == 0 ) { desiredRulesType = URBNF_SPELLOUT; } } else { nsLoc = desiredLocale; nsRuleSetName.setTo(nsDesc); } RuleBasedNumberFormat *r = new RuleBasedNumberFormat(desiredRulesType,nsLoc,status); if (r == NULL) { status = U_MEMORY_ALLOCATION_ERROR; return NULL; } r->setDefaultRuleSet(nsRuleSetName,status); f = r; } else { // replace single currency sign in the pattern with double currency sign // if the style is UNUM_CURRENCY_ISO if (style == UNUM_CURRENCY_ISO) { pattern.findAndReplace(UnicodeString(TRUE, gSingleCurrencySign, 1), UnicodeString(TRUE, gDoubleCurrencySign, 2)); } // "new DecimalFormat()" does not adopt the symbols if its memory allocation fails. DecimalFormatSymbols *syms = symbolsToAdopt.orphan(); f = new DecimalFormat(pattern, syms, style, status); if (f == NULL) { delete syms; status = U_MEMORY_ALLOCATION_ERROR; return NULL; } } f->setLocaleIDs(ures_getLocaleByType(ownedResource.getAlias(), ULOC_VALID_LOCALE, &status), ures_getLocaleByType(ownedResource.getAlias(), ULOC_ACTUAL_LOCALE, &status)); if (U_FAILURE(status)) { delete f; return NULL; } return f; }