UConverter * ucnv_createAlgorithmicConverter(UConverter *myUConverter, UConverterType type, const char *locale, uint32_t options, UErrorCode *err) { UConverter *cnv; const UConverterSharedData *sharedData; UBool isAlgorithmicConverter; UTRACE_ENTRY_OC(UTRACE_UCNV_OPEN_ALGORITHMIC); UTRACE_DATA1(UTRACE_OPEN_CLOSE, "open algorithmic converter type %d", (int32_t)type); if(type<0 || UCNV_NUMBER_OF_SUPPORTED_CONVERTER_TYPES<=type) { *err = U_ILLEGAL_ARGUMENT_ERROR; UTRACE_EXIT_STATUS(U_ILLEGAL_ARGUMENT_ERROR); return NULL; } sharedData = converterData[type]; umtx_lock(&cnvCacheMutex); isAlgorithmicConverter = (UBool)(sharedData == NULL || sharedData->referenceCounter != ~0); umtx_unlock(&cnvCacheMutex); if (isAlgorithmicConverter) { /* not a valid type, or not an algorithmic converter */ *err = U_ILLEGAL_ARGUMENT_ERROR; UTRACE_EXIT_STATUS(U_ILLEGAL_ARGUMENT_ERROR); return NULL; } cnv = ucnv_createConverterFromSharedData(myUConverter, (UConverterSharedData *)sharedData, "", locale != NULL ? locale : "", options, err); UTRACE_EXIT_PTR_STATUS(cnv, *err); return cnv; }
UConverter * ucnv_createConverter(UConverter *myUConverter, const char *converterName, UErrorCode * err) { UConverterLookupData stackLookup; UConverterSharedData *mySharedConverterData; UTRACE_ENTRY_OC(UTRACE_UCNV_OPEN); if(U_SUCCESS(*err)) { UTRACE_DATA1(UTRACE_OPEN_CLOSE, "open converter %s", converterName); mySharedConverterData = ucnv_loadSharedData(converterName, &stackLookup, err); if(U_SUCCESS(*err)) { myUConverter = ucnv_createConverterFromSharedData( myUConverter, mySharedConverterData, stackLookup.realName, stackLookup.locale, stackLookup.options, err); if(U_SUCCESS(*err)) { UTRACE_EXIT_PTR_STATUS(myUConverter, *err); return myUConverter; } else { ucnv_unloadSharedDataIfReady(mySharedConverterData); } } } /* exit with error */ UTRACE_EXIT_STATUS(*err); return NULL; }
U_CAPI void U_EXPORT2 ucol_close(UCollator *coll) { UTRACE_ENTRY_OC(UTRACE_UCOL_CLOSE); UTRACE_DATA1(UTRACE_INFO, "coll = %p", coll); if(coll != NULL) { delete Collator::fromUCollator(coll); } UTRACE_EXIT(); }
U_CAPI UCollator* ucol_open(const char *loc, UErrorCode *status) { U_NAMESPACE_USE UTRACE_ENTRY_OC(UTRACE_UCOL_OPEN); UTRACE_DATA1(UTRACE_INFO, "locale = \"%s\"", loc); UCollator *result = NULL; u_init(status); #if !UCONFIG_NO_SERVICE result = Collator::createUCollator(loc, status); if (result == NULL) #endif { result = ucol_open_internal(loc, status); } UTRACE_EXIT_PTR_STATUS(result, *status); return result; }
U_CAPI UCollator* U_EXPORT2 ucol_openFromShortString( const char *definition, UBool forceDefaults, UParseError *parseError, UErrorCode *status) { UTRACE_ENTRY_OC(UTRACE_UCOL_OPEN_FROM_SHORT_STRING); UTRACE_DATA1(UTRACE_INFO, "short string = \"%s\"", definition); if(U_FAILURE(*status)) return 0; UParseError internalParseError; if(!parseError) { parseError = &internalParseError; } parseError->line = 0; parseError->offset = 0; parseError->preContext[0] = 0; parseError->postContext[0] = 0; // first we want to pick stuff out of short string. // we'll end up with an UCA version, locale and a bunch of // settings // analyse the string in order to get everything we need. const char *string = definition; CollatorSpec s; ucol_sit_initCollatorSpecs(&s); string = ucol_sit_readSpecs(&s, definition, parseError, status); ucol_sit_calculateWholeLocale(&s); char buffer[internalBufferSize]; uprv_memset(buffer, 0, internalBufferSize); uloc_canonicalize(s.locale, buffer, internalBufferSize, status); UCollator *result = ucol_open(buffer, status); int32_t i = 0; for(i = 0; i < UCOL_ATTRIBUTE_COUNT; i++) { if(s.options[i] != UCOL_DEFAULT) { if(forceDefaults || ucol_getAttribute(result, (UColAttribute)i, status) != s.options[i]) { ucol_setAttribute(result, (UColAttribute)i, s.options[i], status); } if(U_FAILURE(*status)) { parseError->offset = (int32_t)(string - definition); ucol_close(result); return NULL; } } } if(s.variableTopSet) { if(s.variableTopString[0]) { ucol_setVariableTop(result, s.variableTopString, s.variableTopStringLen, status); } else { // we set by value, using 'B' ucol_restoreVariableTop(result, s.variableTopValue, status); } } if(U_FAILURE(*status)) { // here it can only be a bogus value ucol_close(result); result = NULL; } UTRACE_EXIT_PTR_STATUS(result, *status); return result; }
/*Frees all shared immutable objects that aren't referred to (reference count = 0) */ U_CAPI int32_t U_EXPORT2 ucnv_flushCache () { UConverterSharedData *mySharedData = NULL; int32_t pos; int32_t tableDeletedNum = 0; const UHashElement *e; UErrorCode status = U_ILLEGAL_ARGUMENT_ERROR; int32_t i, remaining; UTRACE_ENTRY_OC(UTRACE_UCNV_FLUSH_CACHE); /* Close the default converter without creating a new one so that everything will be flushed. */ ucnv_close(u_getDefaultConverter(&status)); /*if shared data hasn't even been lazy evaluated yet * return 0 */ if (SHARED_DATA_HASHTABLE == NULL) { UTRACE_EXIT_VALUE((int32_t)0); return 0; } /*creates an enumeration to iterate through every element in the * table * * Synchronization: holding cnvCacheMutex will prevent any other thread from * accessing or modifying the hash table during the iteration. * The reference count of an entry may be decremented by * ucnv_close while the iteration is in process, but this is * benign. It can't be incremented (in ucnv_createConverter()) * because the sequence of looking up in the cache + incrementing * is protected by cnvCacheMutex. */ umtx_lock(&cnvCacheMutex); /* * double loop: A delta/extension-only converter has a pointer to its base table's * shared data; the first iteration of the outer loop may see the delta converter * before the base converter, and unloading the delta converter may get the base * converter's reference counter down to 0. */ i = 0; do { remaining = 0; pos = -1; while ((e = uhash_nextElement (SHARED_DATA_HASHTABLE, &pos)) != NULL) { mySharedData = (UConverterSharedData *) e->value.pointer; /*deletes only if reference counter == 0 */ if (mySharedData->referenceCounter == 0) { tableDeletedNum++; UCNV_DEBUG_LOG("del",mySharedData->staticData->name,mySharedData); uhash_removeElement(SHARED_DATA_HASHTABLE, e); mySharedData->sharedDataCached = FALSE; ucnv_deleteSharedConverterData (mySharedData); } else { ++remaining; } } } while(++i == 1 && remaining > 0); umtx_unlock(&cnvCacheMutex); UTRACE_DATA1(UTRACE_INFO, "ucnv_flushCache() exits with %d converters remaining", remaining); ucnv_io_flushAvailableConverterCache(); UTRACE_EXIT_VALUE(tableDeletedNum); return tableDeletedNum; }