• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  ******************************************************************************
3  * Copyright (C) 1996-2007, International Business Machines Corporation and   *
4  * others. All Rights Reserved.                                               *
5  ******************************************************************************
6  */
7 
8 /**
9  * File coll.cpp
10  *
11  * Created by: Helena Shih
12  *
13  * Modification History:
14  *
15  *  Date        Name        Description
16  *  2/5/97      aliu        Modified createDefault to load collation data from
17  *                          binary files when possible.  Added related methods
18  *                          createCollationFromFile, chopLocale, createPathName.
19  *  2/11/97     aliu        Added methods addToCache, findInCache, which implement
20  *                          a Collation cache.  Modified createDefault to look in
21  *                          cache first, and also to store newly created Collation
22  *                          objects in the cache.  Modified to not use gLocPath.
23  *  2/12/97     aliu        Modified to create objects from RuleBasedCollator cache.
24  *                          Moved cache out of Collation class.
25  *  2/13/97     aliu        Moved several methods out of this class and into
26  *                          RuleBasedCollator, with modifications.  Modified
27  *                          createDefault() to call new RuleBasedCollator(Locale&)
28  *                          constructor.  General clean up and documentation.
29  *  2/20/97     helena      Added clone, operator==, operator!=, operator=, and copy
30  *                          constructor.
31  * 05/06/97     helena      Added memory allocation error detection.
32  * 05/08/97     helena      Added createInstance().
33  *  6/20/97     helena      Java class name change.
34  * 04/23/99     stephen     Removed EDecompositionMode, merged with
35  *                          Normalizer::EMode
36  * 11/23/9      srl         Inlining of some critical functions
37  * 01/29/01     synwee      Modified into a C++ wrapper calling C APIs (ucol.h)
38  */
39 
40 #include "unicode/utypes.h"
41 
42 #if !UCONFIG_NO_COLLATION
43 
44 #include "unicode/coll.h"
45 #include "unicode/tblcoll.h"
46 #include "ucol_imp.h"
47 #include "cstring.h"
48 #include "cmemory.h"
49 #include "umutex.h"
50 #include "servloc.h"
51 #include "ustrenum.h"
52 #include "ucln_in.h"
53 
54 static U_NAMESPACE_QUALIFIER Locale* availableLocaleList = NULL;
55 static int32_t  availableLocaleListCount;
56 static U_NAMESPACE_QUALIFIER ICULocaleService* gService = NULL;
57 
58 /**
59  * Release all static memory held by collator.
60  */
61 U_CDECL_BEGIN
collator_cleanup(void)62 static UBool U_CALLCONV collator_cleanup(void) {
63 #if !UCONFIG_NO_SERVICE
64     if (gService) {
65         delete gService;
66         gService = NULL;
67     }
68 #endif
69     if (availableLocaleList) {
70         delete []availableLocaleList;
71         availableLocaleList = NULL;
72     }
73     availableLocaleListCount = 0;
74 
75     return TRUE;
76 }
77 
78 U_CDECL_END
79 
80 U_NAMESPACE_BEGIN
81 
82 #if !UCONFIG_NO_SERVICE
83 
84 // ------------------------------------------
85 //
86 // Registration
87 //
88 
89 //-------------------------------------------
90 
~CollatorFactory()91 CollatorFactory::~CollatorFactory() {}
92 
93 //-------------------------------------------
94 
95 UBool
visible(void) const96 CollatorFactory::visible(void) const {
97     return TRUE;
98 }
99 
100 //-------------------------------------------
101 
102 UnicodeString&
getDisplayName(const Locale & objectLocale,const Locale & displayLocale,UnicodeString & result)103 CollatorFactory::getDisplayName(const Locale& objectLocale,
104                                 const Locale& displayLocale,
105                                 UnicodeString& result)
106 {
107   return objectLocale.getDisplayName(displayLocale, result);
108 }
109 
110 // -------------------------------------
111 
112 class ICUCollatorFactory : public ICUResourceBundleFactory {
113  public:
ICUCollatorFactory()114     ICUCollatorFactory():  ICUResourceBundleFactory(UnicodeString(U_ICUDATA_COLL, -1, US_INV)) { }
115  protected:
116     virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
117 };
118 
119 UObject*
create(const ICUServiceKey & key,const ICUService *,UErrorCode & status) const120 ICUCollatorFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const {
121     if (handlesKey(key, status)) {
122         const LocaleKey& lkey = (const LocaleKey&)key;
123         Locale loc;
124         // make sure the requested locale is correct
125         // default LocaleFactory uses currentLocale since that's the one vetted by handlesKey
126         // but for ICU rb resources we use the actual one since it will fallback again
127         lkey.canonicalLocale(loc);
128 
129         return Collator::makeInstance(loc, status);
130     }
131     return NULL;
132 }
133 
134 // -------------------------------------
135 
136 class ICUCollatorService : public ICULocaleService {
137 public:
ICUCollatorService()138     ICUCollatorService()
139         : ICULocaleService(UNICODE_STRING_SIMPLE("Collator"))
140     {
141         UErrorCode status = U_ZERO_ERROR;
142         registerFactory(new ICUCollatorFactory(), status);
143     }
144 
cloneInstance(UObject * instance) const145     virtual UObject* cloneInstance(UObject* instance) const {
146         return ((Collator*)instance)->clone();
147     }
148 
handleDefault(const ICUServiceKey & key,UnicodeString * actualID,UErrorCode & status) const149     virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* actualID, UErrorCode& status) const {
150         LocaleKey& lkey = (LocaleKey&)key;
151         if (actualID) {
152             // Ugly Hack Alert! We return an empty actualID to signal
153             // to callers that this is a default object, not a "real"
154             // service-created object. (TODO remove in 3.0) [aliu]
155             actualID->truncate(0);
156         }
157         Locale loc("");
158         lkey.canonicalLocale(loc);
159         return Collator::makeInstance(loc, status);
160     }
161 
getKey(ICUServiceKey & key,UnicodeString * actualReturn,UErrorCode & status) const162     virtual UObject* getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const {
163         UnicodeString ar;
164         if (actualReturn == NULL) {
165             actualReturn = &ar;
166         }
167         Collator* result = (Collator*)ICULocaleService::getKey(key, actualReturn, status);
168         // Ugly Hack Alert! If the actualReturn length is zero, this
169         // means we got a default object, not a "real" service-created
170         // object.  We don't call setLocales() on a default object,
171         // because that will overwrite its correct built-in locale
172         // metadata (valid & actual) with our incorrect data (all we
173         // have is the requested locale). (TODO remove in 3.0) [aliu]
174         if (result && actualReturn->length() > 0) {
175             const LocaleKey& lkey = (const LocaleKey&)key;
176             Locale canonicalLocale("");
177             Locale currentLocale("");
178 
179             result->setLocales(lkey.canonicalLocale(canonicalLocale),
180                 LocaleUtility::initLocaleFromName(*actualReturn, currentLocale));
181         }
182         return result;
183     }
184 
isDefault() const185     virtual UBool isDefault() const {
186         return countFactories() == 1;
187     }
188 };
189 
190 // -------------------------------------
191 
192 static ICULocaleService*
getService(void)193 getService(void)
194 {
195     UBool needInit;
196     UMTX_CHECK(NULL, (UBool)(gService == NULL), needInit);
197     if(needInit) {
198         ICULocaleService *newservice = new ICUCollatorService();
199         if(newservice) {
200             umtx_lock(NULL);
201             if(gService == NULL) {
202                 gService = newservice;
203                 newservice = NULL;
204             }
205             umtx_unlock(NULL);
206         }
207         if(newservice) {
208             delete newservice;
209         }
210         else {
211             ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
212         }
213     }
214     return gService;
215 }
216 
217 // -------------------------------------
218 
219 static inline UBool
hasService(void)220 hasService(void)
221 {
222     UBool retVal;
223     UMTX_CHECK(NULL, gService != NULL, retVal);
224     return retVal;
225 }
226 
227 // -------------------------------------
228 
229 UCollator*
createUCollator(const char * loc,UErrorCode * status)230 Collator::createUCollator(const char *loc,
231                           UErrorCode *status)
232 {
233     UCollator *result = 0;
234     if (status && U_SUCCESS(*status) && hasService()) {
235         Locale desiredLocale(loc);
236         Collator *col = (Collator*)gService->get(desiredLocale, *status);
237         if (col && col->getDynamicClassID() == RuleBasedCollator::getStaticClassID()) {
238             RuleBasedCollator *rbc = (RuleBasedCollator *)col;
239             if (!rbc->dataIsOwned) {
240                 result = ucol_safeClone(rbc->ucollator, NULL, NULL, status);
241             } else {
242                 result = rbc->ucollator;
243                 rbc->ucollator = NULL; // to prevent free on delete
244             }
245         }
246         delete col;
247     }
248     return result;
249 }
250 #endif /* UCONFIG_NO_SERVICE */
251 
isAvailableLocaleListInitialized(UErrorCode & status)252 static UBool isAvailableLocaleListInitialized(UErrorCode &status) {
253     // for now, there is a hardcoded list, so just walk through that list and set it up.
254     UBool needInit;
255     UMTX_CHECK(NULL, availableLocaleList == NULL, needInit);
256 
257     if (needInit) {
258         UResourceBundle *index = NULL;
259         UResourceBundle installed;
260         Locale * temp;
261         int32_t i = 0;
262         int32_t localeCount;
263 
264         ures_initStackObject(&installed);
265         index = ures_openDirect(U_ICUDATA_COLL, "res_index", &status);
266         ures_getByKey(index, "InstalledLocales", &installed, &status);
267 
268         if(U_SUCCESS(status)) {
269             localeCount = ures_getSize(&installed);
270             temp = new Locale[localeCount];
271 
272             if (temp != NULL) {
273                 ures_resetIterator(&installed);
274                 while(ures_hasNext(&installed)) {
275                     const char *tempKey = NULL;
276                     ures_getNextString(&installed, NULL, &tempKey, &status);
277                     temp[i++] = Locale(tempKey);
278                 }
279 
280                 umtx_lock(NULL);
281                 if (availableLocaleList == NULL)
282                 {
283                     availableLocaleList = temp;
284                     availableLocaleListCount = localeCount;
285                     temp = NULL;
286                     ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
287                 }
288                 umtx_unlock(NULL);
289 
290                 needInit = FALSE;
291                 if (temp) {
292                     delete []temp;
293                 }
294             }
295 
296             ures_close(&installed);
297         }
298         ures_close(index);
299     }
300     return !needInit;
301 }
302 
303 // Collator public methods -----------------------------------------------
304 
createInstance(UErrorCode & success)305 Collator* U_EXPORT2 Collator::createInstance(UErrorCode& success)
306 {
307     return createInstance(Locale::getDefault(), success);
308 }
309 
createInstance(const Locale & desiredLocale,UErrorCode & status)310 Collator* U_EXPORT2 Collator::createInstance(const Locale& desiredLocale,
311                                    UErrorCode& status)
312 {
313     if (U_FAILURE(status))
314         return 0;
315 
316 #if !UCONFIG_NO_SERVICE
317     if (hasService()) {
318         Locale actualLoc;
319         Collator *result =
320             (Collator*)gService->get(desiredLocale, &actualLoc, status);
321         // Ugly Hack Alert! If the returned locale is empty (not root,
322         // but empty -- getName() == "") then that means the service
323         // returned a default object, not a "real" service object.  In
324         // that case, the locale metadata (valid & actual) is setup
325         // correctly already, and we don't want to overwrite it. (TODO
326         // remove in 3.0) [aliu]
327         if (*actualLoc.getName() != 0) {
328             result->setLocales(desiredLocale, actualLoc);
329         }
330         return result;
331     }
332 #endif
333     return makeInstance(desiredLocale, status);
334 }
335 
336 
makeInstance(const Locale & desiredLocale,UErrorCode & status)337 Collator* Collator::makeInstance(const Locale&  desiredLocale,
338                                          UErrorCode& status)
339 {
340     // A bit of explanation is required here. Although in the current
341     // implementation
342     // Collator::createInstance() is just turning around and calling
343     // RuleBasedCollator(Locale&), this will not necessarily always be the
344     // case. For example, suppose we modify this code to handle a
345     // non-table-based Collator, such as that for Thai. In this case,
346     // createInstance() will have to be modified to somehow determine this fact
347     // (perhaps a field in the resource bundle). Then it can construct the
348     // non-table-based Collator in some other way, when it sees that it needs
349     // to.
350     // The specific caution is this: RuleBasedCollator(Locale&) will ALWAYS
351     // return a valid collation object, if the system if functioning properly.
352     // The reason is that it will fall back, use the default locale, and even
353     // use the built-in default collation rules. THEREFORE, createInstance()
354     // should in general ONLY CALL RuleBasedCollator(Locale&) IF IT KNOWS IN
355     // ADVANCE that the given locale's collation is properly implemented as a
356     // RuleBasedCollator.
357     // Currently, we don't do this...we always return a RuleBasedCollator,
358     // whether it is strictly correct to do so or not, without checking, because
359     // we currently have no way of checking.
360 
361     RuleBasedCollator* collation = new RuleBasedCollator(desiredLocale,
362         status);
363     /* test for NULL */
364     if (collation == 0) {
365         status = U_MEMORY_ALLOCATION_ERROR;
366         return 0;
367     }
368     if (U_FAILURE(status))
369     {
370         delete collation;
371         collation = 0;
372     }
373     return collation;
374 }
375 
376 #ifdef U_USE_COLLATION_OBSOLETE_2_6
377 // !!! dlf the following is obsolete, ignore registration for this
378 
379 Collator *
createInstance(const Locale & loc,UVersionInfo version,UErrorCode & status)380 Collator::createInstance(const Locale &loc,
381                          UVersionInfo version,
382                          UErrorCode &status)
383 {
384     Collator *collator;
385     UVersionInfo info;
386 
387     collator=new RuleBasedCollator(loc, status);
388     /* test for NULL */
389     if (collator == 0) {
390         status = U_MEMORY_ALLOCATION_ERROR;
391         return 0;
392     }
393 
394     if(U_SUCCESS(status)) {
395         collator->getVersion(info);
396         if(0!=uprv_memcmp(version, info, sizeof(UVersionInfo))) {
397             delete collator;
398             status=U_MISSING_RESOURCE_ERROR;
399             return 0;
400         }
401     }
402     return collator;
403 }
404 #endif
405 
406 // implement deprecated, previously abstract method
compare(const UnicodeString & source,const UnicodeString & target) const407 Collator::EComparisonResult Collator::compare(const UnicodeString& source,
408                                     const UnicodeString& target) const
409 {
410     UErrorCode ec = U_ZERO_ERROR;
411     return (Collator::EComparisonResult)compare(source, target, ec);
412 }
413 
414 // implement deprecated, previously abstract method
compare(const UnicodeString & source,const UnicodeString & target,int32_t length) const415 Collator::EComparisonResult Collator::compare(const UnicodeString& source,
416                                     const UnicodeString& target,
417                                     int32_t length) const
418 {
419     UErrorCode ec = U_ZERO_ERROR;
420     return (Collator::EComparisonResult)compare(source, target, length, ec);
421 }
422 
423 // implement deprecated, previously abstract method
compare(const UChar * source,int32_t sourceLength,const UChar * target,int32_t targetLength) const424 Collator::EComparisonResult Collator::compare(const UChar* source, int32_t sourceLength,
425                                     const UChar* target, int32_t targetLength)
426                                     const
427 {
428     UErrorCode ec = U_ZERO_ERROR;
429     return (Collator::EComparisonResult)compare(source, sourceLength, target, targetLength, ec);
430 }
431 
equals(const UnicodeString & source,const UnicodeString & target) const432 UBool Collator::equals(const UnicodeString& source,
433                        const UnicodeString& target) const
434 {
435     UErrorCode ec = U_ZERO_ERROR;
436     return (compare(source, target, ec) == UCOL_EQUAL);
437 }
438 
greaterOrEqual(const UnicodeString & source,const UnicodeString & target) const439 UBool Collator::greaterOrEqual(const UnicodeString& source,
440                                const UnicodeString& target) const
441 {
442     UErrorCode ec = U_ZERO_ERROR;
443     return (compare(source, target, ec) != UCOL_LESS);
444 }
445 
greater(const UnicodeString & source,const UnicodeString & target) const446 UBool Collator::greater(const UnicodeString& source,
447                         const UnicodeString& target) const
448 {
449     UErrorCode ec = U_ZERO_ERROR;
450     return (compare(source, target, ec) == UCOL_GREATER);
451 }
452 
453 // this API  ignores registered collators, since it returns an
454 // array of indefinite lifetime
getAvailableLocales(int32_t & count)455 const Locale* U_EXPORT2 Collator::getAvailableLocales(int32_t& count)
456 {
457     UErrorCode status = U_ZERO_ERROR;
458     Locale *result = NULL;
459     count = 0;
460     if (isAvailableLocaleListInitialized(status))
461     {
462         result = availableLocaleList;
463         count = availableLocaleListCount;
464     }
465     return result;
466 }
467 
getDisplayName(const Locale & objectLocale,const Locale & displayLocale,UnicodeString & name)468 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
469                                         const Locale& displayLocale,
470                                         UnicodeString& name)
471 {
472 #if !UCONFIG_NO_SERVICE
473     if (hasService()) {
474         UnicodeString locNameStr;
475         LocaleUtility::initNameFromLocale(objectLocale, locNameStr);
476         return gService->getDisplayName(locNameStr, name, displayLocale);
477     }
478 #endif
479     return objectLocale.getDisplayName(displayLocale, name);
480 }
481 
getDisplayName(const Locale & objectLocale,UnicodeString & name)482 UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
483                                         UnicodeString& name)
484 {
485     return getDisplayName(objectLocale, Locale::getDefault(), name);
486 }
487 
488 /* This is useless information */
489 /*void Collator::getVersion(UVersionInfo versionInfo) const
490 {
491   if (versionInfo!=NULL)
492     uprv_memcpy(versionInfo, fVersion, U_MAX_VERSION_LENGTH);
493 }
494 */
495 
496 // UCollator protected constructor destructor ----------------------------
497 
498 /**
499 * Default constructor.
500 * Constructor is different from the old default Collator constructor.
501 * The task for determing the default collation strength and normalization mode
502 * is left to the child class.
503 */
Collator()504 Collator::Collator()
505 : UObject()
506 {
507 }
508 
509 /**
510 * Constructor.
511 * Empty constructor, does not handle the arguments.
512 * This constructor is done for backward compatibility with 1.7 and 1.8.
513 * The task for handling the argument collation strength and normalization
514 * mode is left to the child class.
515 * @param collationStrength collation strength
516 * @param decompositionMode
517 * @deprecated 2.4 use the default constructor instead
518 */
Collator(UCollationStrength,UNormalizationMode)519 Collator::Collator(UCollationStrength, UNormalizationMode )
520 : UObject()
521 {
522 }
523 
~Collator()524 Collator::~Collator()
525 {
526 }
527 
Collator(const Collator & other)528 Collator::Collator(const Collator &other)
529     : UObject(other)
530 {
531 }
532 
operator ==(const Collator & other) const533 UBool Collator::operator==(const Collator& other) const
534 {
535     return (UBool)(this == &other);
536 }
537 
operator !=(const Collator & other) const538 UBool Collator::operator!=(const Collator& other) const
539 {
540     return (UBool)!(*this == other);
541 }
542 
getBound(const uint8_t * source,int32_t sourceLength,UColBoundMode boundType,uint32_t noOfLevels,uint8_t * result,int32_t resultLength,UErrorCode & status)543 int32_t U_EXPORT2 Collator::getBound(const uint8_t       *source,
544                            int32_t             sourceLength,
545                            UColBoundMode       boundType,
546                            uint32_t            noOfLevels,
547                            uint8_t             *result,
548                            int32_t             resultLength,
549                            UErrorCode          &status)
550 {
551     return ucol_getBound(source, sourceLength, boundType, noOfLevels, result, resultLength, &status);
552 }
553 
554 void
setLocales(const Locale &,const Locale &)555 Collator::setLocales(const Locale& /* requestedLocale */, const Locale& /* validLocale */) {
556 }
557 
getTailoredSet(UErrorCode & status) const558 UnicodeSet *Collator::getTailoredSet(UErrorCode &status) const
559 {
560     if(U_FAILURE(status)) {
561         return NULL;
562     }
563     // everything can be changed
564     return new UnicodeSet(0, 0x10FFFF);
565 }
566 
567 // -------------------------------------
568 
569 #if !UCONFIG_NO_SERVICE
570 URegistryKey U_EXPORT2
registerInstance(Collator * toAdopt,const Locale & locale,UErrorCode & status)571 Collator::registerInstance(Collator* toAdopt, const Locale& locale, UErrorCode& status)
572 {
573     if (U_SUCCESS(status)) {
574         return getService()->registerInstance(toAdopt, locale, status);
575     }
576     return NULL;
577 }
578 
579 // -------------------------------------
580 
581 class CFactory : public LocaleKeyFactory {
582 private:
583     CollatorFactory* _delegate;
584     Hashtable* _ids;
585 
586 public:
CFactory(CollatorFactory * delegate,UErrorCode & status)587     CFactory(CollatorFactory* delegate, UErrorCode& status)
588         : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE)
589         , _delegate(delegate)
590         , _ids(NULL)
591     {
592         if (U_SUCCESS(status)) {
593             int32_t count = 0;
594             _ids = new Hashtable(status);
595             if (_ids) {
596                 const UnicodeString * idlist = _delegate->getSupportedIDs(count, status);
597                 for (int i = 0; i < count; ++i) {
598                     _ids->put(idlist[i], (void*)this, status);
599                     if (U_FAILURE(status)) {
600                         delete _ids;
601                         _ids = NULL;
602                         return;
603                     }
604                 }
605             } else {
606                 status = U_MEMORY_ALLOCATION_ERROR;
607             }
608         }
609     }
610 
~CFactory()611     virtual ~CFactory()
612     {
613         delete _delegate;
614         delete _ids;
615     }
616 
617     virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
618 
619 protected:
getSupportedIDs(UErrorCode & status) const620     virtual const Hashtable* getSupportedIDs(UErrorCode& status) const
621     {
622         if (U_SUCCESS(status)) {
623             return _ids;
624         }
625         return NULL;
626     }
627 
628     virtual UnicodeString&
629         getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const;
630 };
631 
632 UObject*
create(const ICUServiceKey & key,const ICUService *,UErrorCode & status) const633 CFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const
634 {
635     if (handlesKey(key, status)) {
636         const LocaleKey& lkey = (const LocaleKey&)key;
637         Locale validLoc;
638         lkey.currentLocale(validLoc);
639         return _delegate->createCollator(validLoc);
640     }
641     return NULL;
642 }
643 
644 UnicodeString&
getDisplayName(const UnicodeString & id,const Locale & locale,UnicodeString & result) const645 CFactory::getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const
646 {
647     if ((_coverage & 0x1) == 0) {
648         UErrorCode status = U_ZERO_ERROR;
649         const Hashtable* ids = getSupportedIDs(status);
650         if (ids && (ids->get(id) != NULL)) {
651             Locale loc;
652             LocaleUtility::initLocaleFromName(id, loc);
653             return _delegate->getDisplayName(loc, locale, result);
654         }
655     }
656     result.setToBogus();
657     return result;
658 }
659 
660 URegistryKey U_EXPORT2
registerFactory(CollatorFactory * toAdopt,UErrorCode & status)661 Collator::registerFactory(CollatorFactory* toAdopt, UErrorCode& status)
662 {
663     if (U_SUCCESS(status)) {
664         CFactory* f = new CFactory(toAdopt, status);
665         if (f) {
666             return getService()->registerFactory(f, status);
667         }
668         status = U_MEMORY_ALLOCATION_ERROR;
669     }
670     return NULL;
671 }
672 
673 // -------------------------------------
674 
675 UBool U_EXPORT2
unregister(URegistryKey key,UErrorCode & status)676 Collator::unregister(URegistryKey key, UErrorCode& status)
677 {
678     if (U_SUCCESS(status)) {
679         if (hasService()) {
680             return gService->unregister(key, status);
681         }
682         status = U_ILLEGAL_ARGUMENT_ERROR;
683     }
684     return FALSE;
685 }
686 #endif /* UCONFIG_NO_SERVICE */
687 
688 class CollationLocaleListEnumeration : public StringEnumeration {
689 private:
690     int32_t index;
691 public:
692     static UClassID U_EXPORT2 getStaticClassID(void);
693     virtual UClassID getDynamicClassID(void) const;
694 public:
CollationLocaleListEnumeration()695     CollationLocaleListEnumeration()
696         : index(0)
697     {
698         // The global variables should already be initialized.
699         //isAvailableLocaleListInitialized(status);
700     }
701 
~CollationLocaleListEnumeration()702     virtual ~CollationLocaleListEnumeration() {
703     }
704 
clone() const705     virtual StringEnumeration * clone() const
706     {
707         CollationLocaleListEnumeration *result = new CollationLocaleListEnumeration();
708         result->index = index;
709         return result;
710     }
711 
count(UErrorCode &) const712     virtual int32_t count(UErrorCode &/*status*/) const {
713         return availableLocaleListCount;
714     }
715 
next(int32_t * resultLength,UErrorCode &)716     virtual const char* next(int32_t* resultLength, UErrorCode& /*status*/) {
717         const char* result;
718         if(index < availableLocaleListCount) {
719             result = availableLocaleList[index++].getName();
720             if(resultLength != NULL) {
721                 *resultLength = uprv_strlen(result);
722             }
723         } else {
724             if(resultLength != NULL) {
725                 *resultLength = 0;
726             }
727             result = NULL;
728         }
729         return result;
730     }
731 
snext(UErrorCode & status)732     virtual const UnicodeString* snext(UErrorCode& status) {
733         int32_t resultLength = 0;
734         const char *s = next(&resultLength, status);
735         return setChars(s, resultLength, status);
736     }
737 
reset(UErrorCode &)738     virtual void reset(UErrorCode& /*status*/) {
739         index = 0;
740     }
741 };
742 
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationLocaleListEnumeration)743 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationLocaleListEnumeration)
744 
745 
746 // -------------------------------------
747 
748 StringEnumeration* U_EXPORT2
749 Collator::getAvailableLocales(void)
750 {
751 #if !UCONFIG_NO_SERVICE
752     if (hasService()) {
753         return getService()->getAvailableLocales();
754     }
755 #endif /* UCONFIG_NO_SERVICE */
756     UErrorCode status = U_ZERO_ERROR;
757     if (isAvailableLocaleListInitialized(status)) {
758         return new CollationLocaleListEnumeration();
759     }
760     return NULL;
761 }
762 
763 StringEnumeration* U_EXPORT2
getKeywords(UErrorCode & status)764 Collator::getKeywords(UErrorCode& status) {
765     // This is a wrapper over ucol_getKeywords
766     UEnumeration* uenum = ucol_getKeywords(&status);
767     if (U_FAILURE(status)) {
768         uenum_close(uenum);
769         return NULL;
770     }
771     return new UStringEnumeration(uenum);
772 }
773 
774 StringEnumeration* U_EXPORT2
getKeywordValues(const char * keyword,UErrorCode & status)775 Collator::getKeywordValues(const char *keyword, UErrorCode& status) {
776     // This is a wrapper over ucol_getKeywordValues
777     UEnumeration* uenum = ucol_getKeywordValues(keyword, &status);
778     if (U_FAILURE(status)) {
779         uenum_close(uenum);
780         return NULL;
781     }
782     return new UStringEnumeration(uenum);
783 }
784 
785 Locale U_EXPORT2
getFunctionalEquivalent(const char * keyword,const Locale & locale,UBool & isAvailable,UErrorCode & status)786 Collator::getFunctionalEquivalent(const char* keyword, const Locale& locale,
787                                   UBool& isAvailable, UErrorCode& status) {
788     // This is a wrapper over ucol_getFunctionalEquivalent
789     char loc[ULOC_FULLNAME_CAPACITY];
790     /*int32_t len =*/ ucol_getFunctionalEquivalent(loc, sizeof(loc),
791                     keyword, locale.getName(), &isAvailable, &status);
792     if (U_FAILURE(status)) {
793         *loc = 0; // root
794     }
795     return Locale::createFromName(loc);
796 }
797 
798 // UCollator private data members ----------------------------------------
799 
800 /* This is useless information */
801 /*const UVersionInfo Collator::fVersion = {1, 1, 0, 0};*/
802 
803 // -------------------------------------
804 
805 U_NAMESPACE_END
806 
807 #endif /* #if !UCONFIG_NO_COLLATION */
808 
809 /* eof */
810