1 /*******************************************************************************
2 * Copyright (C) 2008-2012, 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 skeletonSet(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 ( skeletonSet.geti(skeletonUniStr) == 1 ) {
281 continue;
282 }
283 skeletonSet.puti(skeletonUniStr, 1, status);
284 if ( uprv_strcmp(skeleton, gFallbackPatternTag) == 0 ) {
285 continue; // fallback
286 }
287
288 LocalUResourceBundlePointer intervalPatterns(ures_getByKey(
289 itvDtPtnResource, skeleton, NULL, &status));
290
291 if ( U_FAILURE(status) ) {
292 break;
293 }
294 if ( intervalPatterns == NULL ) {
295 continue;
296 }
297
298 const char* key;
299 int32_t ptnNum = ures_getSize(intervalPatterns.getAlias());
300 int32_t ptnIndex;
301 for ( ptnIndex = 0; ptnIndex < ptnNum; ++ptnIndex ) {
302 UnicodeString pattern =
303 ures_getNextUnicodeString(intervalPatterns.getAlias(), &key, &status);
304 if ( U_FAILURE(status) ) {
305 break;
306 }
307
308 UCalendarDateFields calendarField = UCAL_FIELD_COUNT;
309 if ( !uprv_strcmp(key, "y") ) {
310 calendarField = UCAL_YEAR;
311 } else if ( !uprv_strcmp(key, "M") ) {
312 calendarField = UCAL_MONTH;
313 } else if ( !uprv_strcmp(key, "d") ) {
314 calendarField = UCAL_DATE;
315 } else if ( !uprv_strcmp(key, "a") ) {
316 calendarField = UCAL_AM_PM;
317 } else if ( !uprv_strcmp(key, "h") || !uprv_strcmp(key, "H") ) {
318 calendarField = UCAL_HOUR;
319 } else if ( !uprv_strcmp(key, "m") ) {
320 calendarField = UCAL_MINUTE;
321 }
322 if ( calendarField != UCAL_FIELD_COUNT ) {
323 setIntervalPatternInternally(skeletonUniStr, calendarField, pattern,status);
324 }
325 }
326 }
327 }
328 }
329 ures_close(itvDtPtnResource);
330 ures_close(calTypeBundle);
331 ures_close(calBundle);
332
333 status = U_ZERO_ERROR;
334 // Find the name of the appropriate parent locale (from %%Parent if present, else
335 // uloc_getParent on the actual locale name)
336 // (It would be nice to have a ures function that did this...)
337 int32_t locNameLen;
338 const UChar * parentUName = ures_getStringByKey(rb, "%%Parent", &locNameLen, &status);
339 if (U_SUCCESS(status) && status != U_USING_FALLBACK_WARNING && locNameLen < ULOC_FULLNAME_CAPACITY) {
340 u_UCharsToChars(parentUName, parentLocale, locNameLen + 1);
341 } else {
342 status = U_ZERO_ERROR;
343 // Get the actual name of the current locale being used
344 const char *curLocaleName=ures_getLocaleByType(rb, ULOC_ACTUAL_LOCALE, &status);
345 if ( U_FAILURE(status) ) {
346 curLocaleName = parentLocale;
347 status = U_ZERO_ERROR;
348 }
349 uloc_getParent(curLocaleName, parentLocale, ULOC_FULLNAME_CAPACITY, &status);
350 if (U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) {
351 parentLocale[0] = 0; // just fallback to root, will cause us to stop
352 status = U_ZERO_ERROR;
353 }
354 }
355 // Now we can close the current locale bundle
356 ures_close(rb);
357 // If the new current locale is root, then stop
358 // (unlike for DateTimePatternGenerator, DateIntervalFormat does not go all the way up
359 // to root to find additional data for non-root locales)
360 } while ( parentLocale[0] != 0 && uprv_strcmp(parentLocale,"root")!=0 );
361 }
362
363
364
365 void
setIntervalPatternInternally(const UnicodeString & skeleton,UCalendarDateFields lrgDiffCalUnit,const UnicodeString & intervalPattern,UErrorCode & status)366 DateIntervalInfo::setIntervalPatternInternally(const UnicodeString& skeleton,
367 UCalendarDateFields lrgDiffCalUnit,
368 const UnicodeString& intervalPattern,
369 UErrorCode& status) {
370 IntervalPatternIndex index = calendarFieldToIntervalIndex(lrgDiffCalUnit,status);
371 if ( U_FAILURE(status) ) {
372 return;
373 }
374 UnicodeString* patternsOfOneSkeleton = (UnicodeString*)(fIntervalPatterns->get(skeleton));
375 UBool emptyHash = false;
376 if ( patternsOfOneSkeleton == NULL ) {
377 patternsOfOneSkeleton = new UnicodeString[kIPI_MAX_INDEX];
378 emptyHash = true;
379 }
380
381 patternsOfOneSkeleton[index] = intervalPattern;
382 if ( emptyHash == TRUE ) {
383 fIntervalPatterns->put(skeleton, patternsOfOneSkeleton, status);
384 }
385 }
386
387
388
389 void
parseSkeleton(const UnicodeString & skeleton,int32_t * skeletonFieldWidth)390 DateIntervalInfo::parseSkeleton(const UnicodeString& skeleton,
391 int32_t* skeletonFieldWidth) {
392 const int8_t PATTERN_CHAR_BASE = 0x41;
393 int32_t i;
394 for ( i = 0; i < skeleton.length(); ++i ) {
395 // it is an ASCII char in skeleton
396 int8_t ch = (int8_t)skeleton.charAt(i);
397 ++skeletonFieldWidth[ch - PATTERN_CHAR_BASE];
398 }
399 }
400
401
402
403 UBool
stringNumeric(int32_t fieldWidth,int32_t anotherFieldWidth,char patternLetter)404 DateIntervalInfo::stringNumeric(int32_t fieldWidth, int32_t anotherFieldWidth,
405 char patternLetter) {
406 if ( patternLetter == 'M' ) {
407 if ( (fieldWidth <= 2 && anotherFieldWidth > 2) ||
408 (fieldWidth > 2 && anotherFieldWidth <= 2 )) {
409 return true;
410 }
411 }
412 return false;
413 }
414
415
416
417 const UnicodeString*
getBestSkeleton(const UnicodeString & skeleton,int8_t & bestMatchDistanceInfo) const418 DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton,
419 int8_t& bestMatchDistanceInfo) const {
420 #ifdef DTITVINF_DEBUG
421 char result[1000];
422 char result_1[1000];
423 char mesg[2000];
424 skeleton.extract(0, skeleton.length(), result, "UTF-8");
425 sprintf(mesg, "in getBestSkeleton: skeleton: %s; \n", result);
426 PRINTMESG(mesg)
427 #endif
428
429
430 int32_t inputSkeletonFieldWidth[] =
431 {
432 // A B C D E F G H I J K L M N O
433 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
434 // P Q R S T U V W X Y Z
435 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
436 // a b c d e f g h i j k l m n o
437 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
438 // p q r s t u v w x y z
439 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
440 };
441
442 int32_t skeletonFieldWidth[] =
443 {
444 // A B C D E F G H I J K L M N O
445 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
446 // P Q R S T U V W X Y Z
447 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
448 // a b c d e f g h i j k l m n o
449 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
450 // p q r s t u v w x y z
451 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
452 };
453
454 const int32_t DIFFERENT_FIELD = 0x1000;
455 const int32_t STRING_NUMERIC_DIFFERENCE = 0x100;
456 const int32_t BASE = 0x41;
457 const UChar CHAR_V = 0x0076;
458 const UChar CHAR_Z = 0x007A;
459
460 // hack for 'v' and 'z'.
461 // resource bundle only have time skeletons ending with 'v',
462 // but not for time skeletons ending with 'z'.
463 UBool replaceZWithV = false;
464 const UnicodeString* inputSkeleton = &skeleton;
465 UnicodeString copySkeleton;
466 if ( skeleton.indexOf(CHAR_Z) != -1 ) {
467 copySkeleton = skeleton;
468 copySkeleton.findAndReplace(UnicodeString(CHAR_Z), UnicodeString(CHAR_V));
469 inputSkeleton = ©Skeleton;
470 replaceZWithV = true;
471 }
472
473 parseSkeleton(*inputSkeleton, inputSkeletonFieldWidth);
474 int32_t bestDistance = MAX_POSITIVE_INT;
475 const UnicodeString* bestSkeleton = NULL;
476
477 // 0 means exact the same skeletons;
478 // 1 means having the same field, but with different length,
479 // 2 means only z/v differs
480 // -1 means having different field.
481 bestMatchDistanceInfo = 0;
482 int8_t fieldLength = sizeof(skeletonFieldWidth)/sizeof(skeletonFieldWidth[0]);
483
484 int32_t pos = -1;
485 const UHashElement* elem = NULL;
486 while ( (elem = fIntervalPatterns->nextElement(pos)) != NULL ) {
487 const UHashTok keyTok = elem->key;
488 UnicodeString* skeleton = (UnicodeString*)keyTok.pointer;
489 #ifdef DTITVINF_DEBUG
490 skeleton->extract(0, skeleton->length(), result, "UTF-8");
491 sprintf(mesg, "available skeletons: skeleton: %s; \n", result);
492 PRINTMESG(mesg)
493 #endif
494
495 // clear skeleton field width
496 int8_t i;
497 for ( i = 0; i < fieldLength; ++i ) {
498 skeletonFieldWidth[i] = 0;
499 }
500 parseSkeleton(*skeleton, skeletonFieldWidth);
501 // calculate distance
502 int32_t distance = 0;
503 int8_t fieldDifference = 1;
504 for ( i = 0; i < fieldLength; ++i ) {
505 int32_t inputFieldWidth = inputSkeletonFieldWidth[i];
506 int32_t fieldWidth = skeletonFieldWidth[i];
507 if ( inputFieldWidth == fieldWidth ) {
508 continue;
509 }
510 if ( inputFieldWidth == 0 ) {
511 fieldDifference = -1;
512 distance += DIFFERENT_FIELD;
513 } else if ( fieldWidth == 0 ) {
514 fieldDifference = -1;
515 distance += DIFFERENT_FIELD;
516 } else if (stringNumeric(inputFieldWidth, fieldWidth,
517 (char)(i+BASE) ) ) {
518 distance += STRING_NUMERIC_DIFFERENCE;
519 } else {
520 distance += (inputFieldWidth > fieldWidth) ?
521 (inputFieldWidth - fieldWidth) :
522 (fieldWidth - inputFieldWidth);
523 }
524 }
525 if ( distance < bestDistance ) {
526 bestSkeleton = skeleton;
527 bestDistance = distance;
528 bestMatchDistanceInfo = fieldDifference;
529 }
530 if ( distance == 0 ) {
531 bestMatchDistanceInfo = 0;
532 break;
533 }
534 }
535 if ( replaceZWithV && bestMatchDistanceInfo != -1 ) {
536 bestMatchDistanceInfo = 2;
537 }
538 return bestSkeleton;
539 }
540
541
542
543 DateIntervalInfo::IntervalPatternIndex
calendarFieldToIntervalIndex(UCalendarDateFields field,UErrorCode & status)544 DateIntervalInfo::calendarFieldToIntervalIndex(UCalendarDateFields field,
545 UErrorCode& status) {
546 if ( U_FAILURE(status) ) {
547 return kIPI_MAX_INDEX;
548 }
549 IntervalPatternIndex index = kIPI_MAX_INDEX;
550 switch ( field ) {
551 case UCAL_ERA:
552 index = kIPI_ERA;
553 break;
554 case UCAL_YEAR:
555 index = kIPI_YEAR;
556 break;
557 case UCAL_MONTH:
558 index = kIPI_MONTH;
559 break;
560 case UCAL_DATE:
561 case UCAL_DAY_OF_WEEK:
562 //case UCAL_DAY_OF_MONTH:
563 index = kIPI_DATE;
564 break;
565 case UCAL_AM_PM:
566 index = kIPI_AM_PM;
567 break;
568 case UCAL_HOUR:
569 case UCAL_HOUR_OF_DAY:
570 index = kIPI_HOUR;
571 break;
572 case UCAL_MINUTE:
573 index = kIPI_MINUTE;
574 break;
575 default:
576 status = U_ILLEGAL_ARGUMENT_ERROR;
577 }
578 return index;
579 }
580
581
582
583 void
deleteHash(Hashtable * hTable)584 DateIntervalInfo::deleteHash(Hashtable* hTable)
585 {
586 if ( hTable == NULL ) {
587 return;
588 }
589 int32_t pos = -1;
590 const UHashElement* element = NULL;
591 while ( (element = hTable->nextElement(pos)) != NULL ) {
592 const UHashTok valueTok = element->value;
593 const UnicodeString* value = (UnicodeString*)valueTok.pointer;
594 delete[] value;
595 }
596 delete fIntervalPatterns;
597 }
598
599
600 U_CDECL_BEGIN
601
602 /**
603 * set hash table value comparator
604 *
605 * @param val1 one value in comparison
606 * @param val2 the other value in comparison
607 * @return TRUE if 2 values are the same, FALSE otherwise
608 */
609 static UBool U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2);
610
611 static UBool
dtitvinfHashTableValueComparator(UHashTok val1,UHashTok val2)612 U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2) {
613 const UnicodeString* pattern1 = (UnicodeString*)val1.pointer;
614 const UnicodeString* pattern2 = (UnicodeString*)val2.pointer;
615 UBool ret = TRUE;
616 int8_t i;
617 for ( i = 0; i < DateIntervalInfo::kMaxIntervalPatternIndex && ret == TRUE; ++i ) {
618 ret = (pattern1[i] == pattern2[i]);
619 }
620 return ret;
621 }
622
623 U_CDECL_END
624
625
626 Hashtable*
initHash(UErrorCode & status)627 DateIntervalInfo::initHash(UErrorCode& status) {
628 if ( U_FAILURE(status) ) {
629 return NULL;
630 }
631 Hashtable* hTable;
632 if ( (hTable = new Hashtable(FALSE, status)) == NULL ) {
633 status = U_MEMORY_ALLOCATION_ERROR;
634 return NULL;
635 }
636 if ( U_FAILURE(status) ) {
637 delete hTable;
638 return NULL;
639 }
640 hTable->setValueComparator(dtitvinfHashTableValueComparator);
641 return hTable;
642 }
643
644
645 void
copyHash(const Hashtable * source,Hashtable * target,UErrorCode & status)646 DateIntervalInfo::copyHash(const Hashtable* source,
647 Hashtable* target,
648 UErrorCode& status) {
649 if ( U_FAILURE(status) ) {
650 return;
651 }
652 int32_t pos = -1;
653 const UHashElement* element = NULL;
654 if ( source ) {
655 while ( (element = source->nextElement(pos)) != NULL ) {
656 const UHashTok keyTok = element->key;
657 const UnicodeString* key = (UnicodeString*)keyTok.pointer;
658 const UHashTok valueTok = element->value;
659 const UnicodeString* value = (UnicodeString*)valueTok.pointer;
660 UnicodeString* copy = new UnicodeString[kIPI_MAX_INDEX];
661 int8_t i;
662 for ( i = 0; i < kIPI_MAX_INDEX; ++i ) {
663 copy[i] = value[i];
664 }
665 target->put(UnicodeString(*key), copy, status);
666 if ( U_FAILURE(status) ) {
667 return;
668 }
669 }
670 }
671 }
672
673
674 U_NAMESPACE_END
675
676 #endif
677