• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2 * Copyright (C) 2008-2015, International Business Machines Corporation and
3 * others. All Rights Reserved.
4 *******************************************************************************
5 *
6 * File DTITVINF.CPP
7 *
8 *******************************************************************************
9 */
10 
11 #include "unicode/dtitvinf.h"
12 
13 
14 #if !UCONFIG_NO_FORMATTING
15 
16 //TODO: define it in compiler time
17 //#define DTITVINF_DEBUG 1
18 
19 
20 #ifdef DTITVINF_DEBUG
21 #include <iostream>
22 #endif
23 
24 #include "cstring.h"
25 #include "unicode/msgfmt.h"
26 #include "unicode/uloc.h"
27 #include "unicode/ures.h"
28 #include "dtitv_impl.h"
29 #include "hash.h"
30 #include "gregoimp.h"
31 #include "uresimp.h"
32 #include "hash.h"
33 #include "gregoimp.h"
34 #include "uresimp.h"
35 
36 
37 U_NAMESPACE_BEGIN
38 
39 
40 #ifdef DTITVINF_DEBUG
41 #define PRINTMESG(msg) { std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; }
42 #endif
43 
44 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalInfo)
45 
46 static const char gCalendarTag[]="calendar";
47 static const char gGregorianTag[]="gregorian";
48 static const char gIntervalDateTimePatternTag[]="intervalFormats";
49 static const char gFallbackPatternTag[]="fallback";
50 
51 // {0}
52 static const UChar gFirstPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET};
53 // {1}
54 static const UChar gSecondPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ONE, RIGHT_CURLY_BRACKET};
55 
56 // default fall-back
57 static const UChar gDefaultFallbackPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, EN_DASH, SPACE, LEFT_CURLY_BRACKET, DIGIT_ONE, RIGHT_CURLY_BRACKET, 0};
58 
59 
60 
DateIntervalInfo(UErrorCode & status)61 DateIntervalInfo::DateIntervalInfo(UErrorCode& status)
62 :   fFallbackIntervalPattern(gDefaultFallbackPattern),
63     fFirstDateInPtnIsLaterDate(false),
64     fIntervalPatterns(NULL)
65 {
66     fIntervalPatterns = initHash(status);
67 }
68 
69 
70 
DateIntervalInfo(const Locale & locale,UErrorCode & status)71 DateIntervalInfo::DateIntervalInfo(const Locale& locale, UErrorCode& status)
72 :   fFallbackIntervalPattern(gDefaultFallbackPattern),
73     fFirstDateInPtnIsLaterDate(false),
74     fIntervalPatterns(NULL)
75 {
76     initializeData(locale, status);
77 }
78 
79 
80 
81 void
setIntervalPattern(const UnicodeString & skeleton,UCalendarDateFields lrgDiffCalUnit,const UnicodeString & intervalPattern,UErrorCode & status)82 DateIntervalInfo::setIntervalPattern(const UnicodeString& skeleton,
83                                      UCalendarDateFields lrgDiffCalUnit,
84                                      const UnicodeString& intervalPattern,
85                                      UErrorCode& status) {
86 
87     if ( lrgDiffCalUnit == UCAL_HOUR_OF_DAY ) {
88         setIntervalPatternInternally(skeleton, UCAL_AM_PM, intervalPattern, status);
89         setIntervalPatternInternally(skeleton, UCAL_HOUR, intervalPattern, status);
90     } else if ( lrgDiffCalUnit == UCAL_DAY_OF_MONTH ||
91                 lrgDiffCalUnit == UCAL_DAY_OF_WEEK ) {
92         setIntervalPatternInternally(skeleton, UCAL_DATE, intervalPattern, status);
93     } else {
94         setIntervalPatternInternally(skeleton, lrgDiffCalUnit, intervalPattern, status);
95     }
96 }
97 
98 
99 void
setFallbackIntervalPattern(const UnicodeString & fallbackPattern,UErrorCode & status)100 DateIntervalInfo::setFallbackIntervalPattern(
101                                     const UnicodeString& fallbackPattern,
102                                     UErrorCode& status) {
103     if ( U_FAILURE(status) ) {
104         return;
105     }
106     int32_t firstPatternIndex = fallbackPattern.indexOf(gFirstPattern,
107                         sizeof(gFirstPattern)/sizeof(gFirstPattern[0]), 0);
108     int32_t secondPatternIndex = fallbackPattern.indexOf(gSecondPattern,
109                         sizeof(gSecondPattern)/sizeof(gSecondPattern[0]), 0);
110     if ( firstPatternIndex == -1 || secondPatternIndex == -1 ) {
111         status = U_ILLEGAL_ARGUMENT_ERROR;
112         return;
113     }
114     if ( firstPatternIndex > secondPatternIndex ) {
115         fFirstDateInPtnIsLaterDate = true;
116     }
117     fFallbackIntervalPattern = fallbackPattern;
118 }
119 
120 
121 
DateIntervalInfo(const DateIntervalInfo & dtitvinf)122 DateIntervalInfo::DateIntervalInfo(const DateIntervalInfo& dtitvinf)
123 :   UObject(dtitvinf),
124     fIntervalPatterns(NULL)
125 {
126     *this = dtitvinf;
127 }
128 
129 
130 
131 DateIntervalInfo&
operator =(const DateIntervalInfo & dtitvinf)132 DateIntervalInfo::operator=(const DateIntervalInfo& dtitvinf) {
133     if ( this == &dtitvinf ) {
134         return *this;
135     }
136 
137     UErrorCode status = U_ZERO_ERROR;
138     deleteHash(fIntervalPatterns);
139     fIntervalPatterns = initHash(status);
140     copyHash(dtitvinf.fIntervalPatterns, fIntervalPatterns, status);
141     if ( U_FAILURE(status) ) {
142         return *this;
143     }
144 
145     fFallbackIntervalPattern = dtitvinf.fFallbackIntervalPattern;
146     fFirstDateInPtnIsLaterDate = dtitvinf.fFirstDateInPtnIsLaterDate;
147     return *this;
148 }
149 
150 
151 DateIntervalInfo*
clone() const152 DateIntervalInfo::clone() const {
153     return new DateIntervalInfo(*this);
154 }
155 
156 
~DateIntervalInfo()157 DateIntervalInfo::~DateIntervalInfo() {
158     deleteHash(fIntervalPatterns);
159     fIntervalPatterns = NULL;
160 }
161 
162 
163 UBool
operator ==(const DateIntervalInfo & other) const164 DateIntervalInfo::operator==(const DateIntervalInfo& other) const {
165     UBool equal = (
166       fFallbackIntervalPattern == other.fFallbackIntervalPattern &&
167       fFirstDateInPtnIsLaterDate == other.fFirstDateInPtnIsLaterDate );
168 
169     if ( equal == TRUE ) {
170         equal = fIntervalPatterns->equals(*(other.fIntervalPatterns));
171     }
172 
173     return equal;
174 }
175 
176 
177 UnicodeString&
getIntervalPattern(const UnicodeString & skeleton,UCalendarDateFields field,UnicodeString & result,UErrorCode & status) const178 DateIntervalInfo::getIntervalPattern(const UnicodeString& skeleton,
179                                      UCalendarDateFields field,
180                                      UnicodeString& result,
181                                      UErrorCode& status) const {
182     if ( U_FAILURE(status) ) {
183         return result;
184     }
185 
186     const UnicodeString* patternsOfOneSkeleton = (UnicodeString*) fIntervalPatterns->get(skeleton);
187     if ( patternsOfOneSkeleton != NULL ) {
188         IntervalPatternIndex index = calendarFieldToIntervalIndex(field, status);
189         if ( U_FAILURE(status) ) {
190             return result;
191         }
192         const UnicodeString& intervalPattern =  patternsOfOneSkeleton[index];
193         if ( !intervalPattern.isEmpty() ) {
194             result = intervalPattern;
195         }
196     }
197     return result;
198 }
199 
200 
201 UBool
getDefaultOrder() const202 DateIntervalInfo::getDefaultOrder() const {
203     return fFirstDateInPtnIsLaterDate;
204 }
205 
206 
207 UnicodeString&
getFallbackIntervalPattern(UnicodeString & result) const208 DateIntervalInfo::getFallbackIntervalPattern(UnicodeString& result) const {
209     result = fFallbackIntervalPattern;
210     return result;
211 }
212 
213 #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
214 
215 void
initializeData(const Locale & locale,UErrorCode & err)216 DateIntervalInfo::initializeData(const Locale& locale, UErrorCode& err)
217 {
218   fIntervalPatterns = initHash(err);
219   if ( U_FAILURE(err) ) {
220       return;
221   }
222   const char *locName = locale.getName();
223   char parentLocale[ULOC_FULLNAME_CAPACITY];
224   uprv_strcpy(parentLocale, locName);
225   UErrorCode status = U_ZERO_ERROR;
226   Hashtable skeletonKeyPairs(FALSE, status);
227   if ( U_FAILURE(status) ) {
228       return;
229   }
230 
231   // determine calendar type
232   const char * calendarTypeToUse = gGregorianTag; // initial default
233   char         calendarType[ULOC_KEYWORDS_CAPACITY]; // to be filled in with the type to use, if all goes well
234   char         localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY];
235   // obtain a locale that always has the calendar key value that should be used
236   (void)ures_getFunctionalEquivalent(localeWithCalendarKey, ULOC_LOCALE_IDENTIFIER_CAPACITY, NULL,
237                                      "calendar", "calendar", locName, NULL, FALSE, &status);
238   localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination
239   // now get the calendar key value from that locale
240   int32_t calendarTypeLen = uloc_getKeywordValue(localeWithCalendarKey, "calendar", calendarType, ULOC_KEYWORDS_CAPACITY, &status);
241   if (U_SUCCESS(status) && calendarTypeLen < ULOC_KEYWORDS_CAPACITY) {
242     calendarTypeToUse = calendarType;
243   }
244   status = U_ZERO_ERROR;
245 
246   do {
247     UResourceBundle *rb, *calBundle, *calTypeBundle, *itvDtPtnResource;
248     rb = ures_open(NULL, parentLocale, &status);
249     if ( U_FAILURE(status) ) {
250         break;
251     }
252     calBundle = ures_getByKey(rb, gCalendarTag, NULL, &status);
253     calTypeBundle = ures_getByKey(calBundle, calendarTypeToUse, NULL, &status);
254     itvDtPtnResource = ures_getByKeyWithFallback(calTypeBundle,
255                          gIntervalDateTimePatternTag, NULL, &status);
256 
257     if ( U_SUCCESS(status) ) {
258         // look for fallback first, since it establishes the default order
259         const UChar* resStr;
260         int32_t resStrLen = 0;
261         resStr = ures_getStringByKeyWithFallback(itvDtPtnResource,
262                                              gFallbackPatternTag,
263                                              &resStrLen, &status);
264         if ( U_SUCCESS(status) ) {
265             UnicodeString pattern = UnicodeString(TRUE, resStr, resStrLen);
266             setFallbackIntervalPattern(pattern, status);
267         }
268 
269         int32_t size = ures_getSize(itvDtPtnResource);
270         int32_t index;
271         for ( index = 0; index < size; ++index ) {
272             LocalUResourceBundlePointer oneRes(ures_getByIndex(itvDtPtnResource, index,
273                                                      NULL, &status));
274             if ( U_SUCCESS(status) ) {
275                 const char* skeleton = ures_getKey(oneRes.getAlias());
276                 if (skeleton == NULL) {
277                     continue;
278                 }
279                 UnicodeString skeletonUniStr(skeleton, -1, US_INV);
280                 if ( uprv_strcmp(skeleton, gFallbackPatternTag) == 0 ) {
281                     continue;  // fallback
282                 }
283 
284                 LocalUResourceBundlePointer intervalPatterns(ures_getByKey(
285                                      itvDtPtnResource, skeleton, NULL, &status));
286 
287                 if ( U_FAILURE(status) ) {
288                     break;
289                 }
290                 if ( intervalPatterns == NULL ) {
291                     continue;
292                 }
293 
294                 const char* key;
295                 int32_t ptnNum = ures_getSize(intervalPatterns.getAlias());
296                 int32_t ptnIndex;
297                 for ( ptnIndex = 0; ptnIndex < ptnNum; ++ptnIndex ) {
298                     UnicodeString pattern =
299                         ures_getNextUnicodeString(intervalPatterns.getAlias(), &key, &status);
300                     if ( U_FAILURE(status) ) {
301                         break;
302                     }
303                     UnicodeString keyUniStr(key, -1, US_INV);
304                     UnicodeString skeletonKeyPair(skeletonUniStr + keyUniStr);
305                     if ( skeletonKeyPairs.geti(skeletonKeyPair) == 1 ) {
306                         continue;
307                     }
308                     skeletonKeyPairs.puti(skeletonKeyPair, 1, status);
309 
310                     UCalendarDateFields calendarField = UCAL_FIELD_COUNT;
311                     if ( !uprv_strcmp(key, "y") ) {
312                         calendarField = UCAL_YEAR;
313                     } else if ( !uprv_strcmp(key, "M") ) {
314                         calendarField = UCAL_MONTH;
315                     } else if ( !uprv_strcmp(key, "d") ) {
316                         calendarField = UCAL_DATE;
317                     } else if ( !uprv_strcmp(key, "a") ) {
318                         calendarField = UCAL_AM_PM;
319                     } else if ( !uprv_strcmp(key, "h") || !uprv_strcmp(key, "H") ) {
320                         calendarField = UCAL_HOUR;
321                     } else if ( !uprv_strcmp(key, "m") ) {
322                         calendarField = UCAL_MINUTE;
323                     }
324                     if ( calendarField != UCAL_FIELD_COUNT ) {
325                         setIntervalPatternInternally(skeletonUniStr, calendarField, pattern,status);
326                     }
327                 }
328             }
329         }
330     }
331     ures_close(itvDtPtnResource);
332     ures_close(calTypeBundle);
333     ures_close(calBundle);
334 
335     status = U_ZERO_ERROR;
336     // Find the name of the appropriate parent locale (from %%Parent if present, else
337     // uloc_getParent on the actual locale name)
338     // (It would be nice to have a ures function that did this...)
339     int32_t locNameLen;
340     const UChar * parentUName = ures_getStringByKey(rb, "%%Parent", &locNameLen, &status);
341     if (U_SUCCESS(status) && status != U_USING_FALLBACK_WARNING && locNameLen < ULOC_FULLNAME_CAPACITY) {
342         u_UCharsToChars(parentUName, parentLocale, locNameLen + 1);
343     } else {
344         status = U_ZERO_ERROR;
345         // Get the actual name of the current locale being used
346         const char *curLocaleName=ures_getLocaleByType(rb, ULOC_ACTUAL_LOCALE, &status);
347         if ( U_FAILURE(status) ) {
348             curLocaleName = parentLocale;
349             status = U_ZERO_ERROR;
350         }
351         uloc_getParent(curLocaleName, parentLocale, ULOC_FULLNAME_CAPACITY, &status);
352         if (U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) {
353             parentLocale[0] = 0; // just fallback to root, will cause us to stop
354             status = U_ZERO_ERROR;
355         }
356     }
357     // Now we can close the current locale bundle
358     ures_close(rb);
359     // If the new current locale is root, then stop
360     // (unlike for DateTimePatternGenerator, DateIntervalFormat does not go all the way up
361     // to root to find additional data for non-root locales)
362   } while ( parentLocale[0] != 0 && uprv_strcmp(parentLocale,"root")!=0 );
363 }
364 
365 
366 
367 void
setIntervalPatternInternally(const UnicodeString & skeleton,UCalendarDateFields lrgDiffCalUnit,const UnicodeString & intervalPattern,UErrorCode & status)368 DateIntervalInfo::setIntervalPatternInternally(const UnicodeString& skeleton,
369                                       UCalendarDateFields lrgDiffCalUnit,
370                                       const UnicodeString& intervalPattern,
371                                       UErrorCode& status) {
372     IntervalPatternIndex index = calendarFieldToIntervalIndex(lrgDiffCalUnit,status);
373     if ( U_FAILURE(status) ) {
374         return;
375     }
376     UnicodeString* patternsOfOneSkeleton = (UnicodeString*)(fIntervalPatterns->get(skeleton));
377     UBool emptyHash = false;
378     if ( patternsOfOneSkeleton == NULL ) {
379         patternsOfOneSkeleton = new UnicodeString[kIPI_MAX_INDEX];
380         emptyHash = true;
381     }
382 
383     patternsOfOneSkeleton[index] = intervalPattern;
384     if ( emptyHash == TRUE ) {
385         fIntervalPatterns->put(skeleton, patternsOfOneSkeleton, status);
386     }
387 }
388 
389 
390 
391 void
parseSkeleton(const UnicodeString & skeleton,int32_t * skeletonFieldWidth)392 DateIntervalInfo::parseSkeleton(const UnicodeString& skeleton,
393                                 int32_t* skeletonFieldWidth) {
394     const int8_t PATTERN_CHAR_BASE = 0x41;
395     int32_t i;
396     for ( i = 0; i < skeleton.length(); ++i ) {
397         // it is an ASCII char in skeleton
398         int8_t ch = (int8_t)skeleton.charAt(i);
399         ++skeletonFieldWidth[ch - PATTERN_CHAR_BASE];
400     }
401 }
402 
403 
404 
405 UBool
stringNumeric(int32_t fieldWidth,int32_t anotherFieldWidth,char patternLetter)406 DateIntervalInfo::stringNumeric(int32_t fieldWidth, int32_t anotherFieldWidth,
407                                 char patternLetter) {
408     if ( patternLetter == 'M' ) {
409         if ( (fieldWidth <= 2 && anotherFieldWidth > 2) ||
410              (fieldWidth > 2 && anotherFieldWidth <= 2 )) {
411             return true;
412         }
413     }
414     return false;
415 }
416 
417 
418 
419 const UnicodeString*
getBestSkeleton(const UnicodeString & skeleton,int8_t & bestMatchDistanceInfo) const420 DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton,
421                                   int8_t& bestMatchDistanceInfo) const {
422 #ifdef DTITVINF_DEBUG
423     char result[1000];
424     char result_1[1000];
425     char mesg[2000];
426     skeleton.extract(0,  skeleton.length(), result, "UTF-8");
427     sprintf(mesg, "in getBestSkeleton: skeleton: %s; \n", result);
428     PRINTMESG(mesg)
429 #endif
430 
431 
432     int32_t inputSkeletonFieldWidth[] =
433     {
434     //       A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
435              0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
436     //   P   Q   R   S   T   U   V   W   X   Y   Z
437          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0,  0, 0, 0,
438     //       a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
439          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
440     //   p   q   r   s   t   u   v   w   x   y   z
441          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
442     };
443 
444     int32_t skeletonFieldWidth[] =
445     {
446     //       A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
447              0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
448     //   P   Q   R   S   T   U   V   W   X   Y   Z
449          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0,  0, 0, 0,
450     //       a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
451          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
452     //   p   q   r   s   t   u   v   w   x   y   z
453          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
454     };
455 
456     const int32_t DIFFERENT_FIELD = 0x1000;
457     const int32_t STRING_NUMERIC_DIFFERENCE = 0x100;
458     const int32_t BASE = 0x41;
459     const UChar CHAR_V = 0x0076;
460     const UChar CHAR_Z = 0x007A;
461 
462     // hack for 'v' and 'z'.
463     // resource bundle only have time skeletons ending with 'v',
464     // but not for time skeletons ending with 'z'.
465     UBool replaceZWithV = false;
466     const UnicodeString* inputSkeleton = &skeleton;
467     UnicodeString copySkeleton;
468     if ( skeleton.indexOf(CHAR_Z) != -1 ) {
469         copySkeleton = skeleton;
470         copySkeleton.findAndReplace(UnicodeString(CHAR_Z), UnicodeString(CHAR_V));
471         inputSkeleton = &copySkeleton;
472         replaceZWithV = true;
473     }
474 
475     parseSkeleton(*inputSkeleton, inputSkeletonFieldWidth);
476     int32_t bestDistance = MAX_POSITIVE_INT;
477     const UnicodeString* bestSkeleton = NULL;
478 
479     // 0 means exact the same skeletons;
480     // 1 means having the same field, but with different length,
481     // 2 means only z/v differs
482     // -1 means having different field.
483     bestMatchDistanceInfo = 0;
484     int8_t fieldLength = sizeof(skeletonFieldWidth)/sizeof(skeletonFieldWidth[0]);
485 
486     int32_t pos = UHASH_FIRST;
487     const UHashElement* elem = NULL;
488     while ( (elem = fIntervalPatterns->nextElement(pos)) != NULL ) {
489         const UHashTok keyTok = elem->key;
490         UnicodeString* skeleton = (UnicodeString*)keyTok.pointer;
491 #ifdef DTITVINF_DEBUG
492     skeleton->extract(0,  skeleton->length(), result, "UTF-8");
493     sprintf(mesg, "available skeletons: skeleton: %s; \n", result);
494     PRINTMESG(mesg)
495 #endif
496 
497         // clear skeleton field width
498         int8_t i;
499         for ( i = 0; i < fieldLength; ++i ) {
500             skeletonFieldWidth[i] = 0;
501         }
502         parseSkeleton(*skeleton, skeletonFieldWidth);
503         // calculate distance
504         int32_t distance = 0;
505         int8_t fieldDifference = 1;
506         for ( i = 0; i < fieldLength; ++i ) {
507             int32_t inputFieldWidth = inputSkeletonFieldWidth[i];
508             int32_t fieldWidth = skeletonFieldWidth[i];
509             if ( inputFieldWidth == fieldWidth ) {
510                 continue;
511             }
512             if ( inputFieldWidth == 0 ) {
513                 fieldDifference = -1;
514                 distance += DIFFERENT_FIELD;
515             } else if ( fieldWidth == 0 ) {
516                 fieldDifference = -1;
517                 distance += DIFFERENT_FIELD;
518             } else if (stringNumeric(inputFieldWidth, fieldWidth,
519                                      (char)(i+BASE) ) ) {
520                 distance += STRING_NUMERIC_DIFFERENCE;
521             } else {
522                 distance += (inputFieldWidth > fieldWidth) ?
523                             (inputFieldWidth - fieldWidth) :
524                             (fieldWidth - inputFieldWidth);
525             }
526         }
527         if ( distance < bestDistance ) {
528             bestSkeleton = skeleton;
529             bestDistance = distance;
530             bestMatchDistanceInfo = fieldDifference;
531         }
532         if ( distance == 0 ) {
533             bestMatchDistanceInfo = 0;
534             break;
535         }
536     }
537     if ( replaceZWithV && bestMatchDistanceInfo != -1 ) {
538         bestMatchDistanceInfo = 2;
539     }
540     return bestSkeleton;
541 }
542 
543 
544 
545 DateIntervalInfo::IntervalPatternIndex
calendarFieldToIntervalIndex(UCalendarDateFields field,UErrorCode & status)546 DateIntervalInfo::calendarFieldToIntervalIndex(UCalendarDateFields field,
547                                                UErrorCode& status) {
548     if ( U_FAILURE(status) ) {
549         return kIPI_MAX_INDEX;
550     }
551     IntervalPatternIndex index = kIPI_MAX_INDEX;
552     switch ( field ) {
553       case UCAL_ERA:
554         index = kIPI_ERA;
555         break;
556       case UCAL_YEAR:
557         index = kIPI_YEAR;
558         break;
559       case UCAL_MONTH:
560         index = kIPI_MONTH;
561         break;
562       case UCAL_DATE:
563       case UCAL_DAY_OF_WEEK:
564       //case UCAL_DAY_OF_MONTH:
565         index = kIPI_DATE;
566         break;
567       case UCAL_AM_PM:
568         index = kIPI_AM_PM;
569         break;
570       case UCAL_HOUR:
571       case UCAL_HOUR_OF_DAY:
572         index = kIPI_HOUR;
573         break;
574       case UCAL_MINUTE:
575         index = kIPI_MINUTE;
576         break;
577       case UCAL_SECOND:
578         index = kIPI_SECOND;
579         break;
580       default:
581         status = U_ILLEGAL_ARGUMENT_ERROR;
582     }
583     return index;
584 }
585 
586 
587 
588 void
deleteHash(Hashtable * hTable)589 DateIntervalInfo::deleteHash(Hashtable* hTable)
590 {
591     if ( hTable == NULL ) {
592         return;
593     }
594     int32_t pos = UHASH_FIRST;
595     const UHashElement* element = NULL;
596     while ( (element = hTable->nextElement(pos)) != NULL ) {
597         const UHashTok valueTok = element->value;
598         const UnicodeString* value = (UnicodeString*)valueTok.pointer;
599         delete[] value;
600     }
601     delete fIntervalPatterns;
602 }
603 
604 
605 U_CDECL_BEGIN
606 
607 /**
608  * set hash table value comparator
609  *
610  * @param val1  one value in comparison
611  * @param val2  the other value in comparison
612  * @return      TRUE if 2 values are the same, FALSE otherwise
613  */
614 static UBool U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2);
615 
616 static UBool
dtitvinfHashTableValueComparator(UHashTok val1,UHashTok val2)617 U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2) {
618     const UnicodeString* pattern1 = (UnicodeString*)val1.pointer;
619     const UnicodeString* pattern2 = (UnicodeString*)val2.pointer;
620     UBool ret = TRUE;
621     int8_t i;
622     for ( i = 0; i < DateIntervalInfo::kMaxIntervalPatternIndex && ret == TRUE; ++i ) {
623         ret = (pattern1[i] == pattern2[i]);
624     }
625     return ret;
626 }
627 
628 U_CDECL_END
629 
630 
631 Hashtable*
initHash(UErrorCode & status)632 DateIntervalInfo::initHash(UErrorCode& status) {
633     if ( U_FAILURE(status) ) {
634         return NULL;
635     }
636     Hashtable* hTable;
637     if ( (hTable = new Hashtable(FALSE, status)) == NULL ) {
638         status = U_MEMORY_ALLOCATION_ERROR;
639         return NULL;
640     }
641     if ( U_FAILURE(status) ) {
642         delete hTable;
643         return NULL;
644     }
645     hTable->setValueComparator(dtitvinfHashTableValueComparator);
646     return hTable;
647 }
648 
649 
650 void
copyHash(const Hashtable * source,Hashtable * target,UErrorCode & status)651 DateIntervalInfo::copyHash(const Hashtable* source,
652                            Hashtable* target,
653                            UErrorCode& status) {
654     if ( U_FAILURE(status) ) {
655         return;
656     }
657     int32_t pos = UHASH_FIRST;
658     const UHashElement* element = NULL;
659     if ( source ) {
660         while ( (element = source->nextElement(pos)) != NULL ) {
661             const UHashTok keyTok = element->key;
662             const UnicodeString* key = (UnicodeString*)keyTok.pointer;
663             const UHashTok valueTok = element->value;
664             const UnicodeString* value = (UnicodeString*)valueTok.pointer;
665             UnicodeString* copy = new UnicodeString[kIPI_MAX_INDEX];
666             int8_t i;
667             for ( i = 0; i < kIPI_MAX_INDEX; ++i ) {
668                 copy[i] = value[i];
669             }
670             target->put(UnicodeString(*key), copy, status);
671             if ( U_FAILURE(status) ) {
672                 return;
673             }
674         }
675     }
676 }
677 
678 
679 U_NAMESPACE_END
680 
681 #endif
682