]>
Commit | Line | Data |
---|---|---|
46f4442e | 1 | /******************************************************************************* |
b331163b | 2 | * Copyright (C) 2008-2015, International Business Machines Corporation and |
46f4442e A |
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 | ||
729e4ab9 | 16 | //TODO: define it in compiler time |
46f4442e A |
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" | |
729e4ab9 A |
26 | #include "unicode/uloc.h" |
27 | #include "unicode/ures.h" | |
46f4442e A |
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 | ||
61 | DateIntervalInfo::DateIntervalInfo(UErrorCode& status) | |
62 | : fFallbackIntervalPattern(gDefaultFallbackPattern), | |
63 | fFirstDateInPtnIsLaterDate(false), | |
64 | fIntervalPatterns(NULL) | |
65 | { | |
66 | fIntervalPatterns = initHash(status); | |
67 | } | |
68 | ||
69 | ||
70 | ||
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 | |
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 | |
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 | ||
122 | DateIntervalInfo::DateIntervalInfo(const DateIntervalInfo& dtitvinf) | |
123 | : UObject(dtitvinf), | |
124 | fIntervalPatterns(NULL) | |
125 | { | |
126 | *this = dtitvinf; | |
127 | } | |
128 | ||
129 | ||
130 | ||
131 | DateIntervalInfo& | |
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* | |
152 | DateIntervalInfo::clone() const { | |
153 | return new DateIntervalInfo(*this); | |
154 | } | |
155 | ||
156 | ||
157 | DateIntervalInfo::~DateIntervalInfo() { | |
158 | deleteHash(fIntervalPatterns); | |
159 | fIntervalPatterns = NULL; | |
160 | } | |
161 | ||
162 | ||
163 | UBool | |
164 | 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& | |
178 | 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 | |
202 | DateIntervalInfo::getDefaultOrder() const { | |
203 | return fFirstDateInPtnIsLaterDate; | |
204 | } | |
205 | ||
206 | ||
207 | UnicodeString& | |
208 | DateIntervalInfo::getFallbackIntervalPattern(UnicodeString& result) const { | |
209 | result = fFallbackIntervalPattern; | |
210 | return result; | |
211 | } | |
212 | ||
729e4ab9 | 213 | #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY) |
46f4442e A |
214 | |
215 | void | |
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]; | |
46f4442e A |
224 | uprv_strcpy(parentLocale, locName); |
225 | UErrorCode status = U_ZERO_ERROR; | |
b331163b | 226 | Hashtable skeletonKeyPairs(FALSE, status); |
46f4442e A |
227 | if ( U_FAILURE(status) ) { |
228 | return; | |
229 | } | |
729e4ab9 A |
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 | ||
46f4442e | 246 | do { |
729e4ab9 | 247 | UResourceBundle *rb, *calBundle, *calTypeBundle, *itvDtPtnResource; |
46f4442e | 248 | rb = ures_open(NULL, parentLocale, &status); |
4388f060 A |
249 | if ( U_FAILURE(status) ) { |
250 | break; | |
251 | } | |
46f4442e | 252 | calBundle = ures_getByKey(rb, gCalendarTag, NULL, &status); |
729e4ab9 A |
253 | calTypeBundle = ures_getByKey(calBundle, calendarTypeToUse, NULL, &status); |
254 | itvDtPtnResource = ures_getByKeyWithFallback(calTypeBundle, | |
46f4442e A |
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 ) { | |
4388f060 A |
272 | LocalUResourceBundlePointer oneRes(ures_getByIndex(itvDtPtnResource, index, |
273 | NULL, &status)); | |
46f4442e | 274 | if ( U_SUCCESS(status) ) { |
4388f060 A |
275 | const char* skeleton = ures_getKey(oneRes.getAlias()); |
276 | if (skeleton == NULL) { | |
277 | continue; | |
278 | } | |
279 | UnicodeString skeletonUniStr(skeleton, -1, US_INV); | |
46f4442e | 280 | if ( uprv_strcmp(skeleton, gFallbackPatternTag) == 0 ) { |
46f4442e A |
281 | continue; // fallback |
282 | } | |
4388f060 A |
283 | |
284 | LocalUResourceBundlePointer intervalPatterns(ures_getByKey( | |
285 | itvDtPtnResource, skeleton, NULL, &status)); | |
286 | ||
46f4442e | 287 | if ( U_FAILURE(status) ) { |
46f4442e A |
288 | break; |
289 | } | |
290 | if ( intervalPatterns == NULL ) { | |
46f4442e A |
291 | continue; |
292 | } | |
4388f060 | 293 | |
46f4442e | 294 | const char* key; |
4388f060 | 295 | int32_t ptnNum = ures_getSize(intervalPatterns.getAlias()); |
46f4442e A |
296 | int32_t ptnIndex; |
297 | for ( ptnIndex = 0; ptnIndex < ptnNum; ++ptnIndex ) { | |
4388f060 A |
298 | UnicodeString pattern = |
299 | ures_getNextUnicodeString(intervalPatterns.getAlias(), &key, &status); | |
46f4442e A |
300 | if ( U_FAILURE(status) ) { |
301 | break; | |
302 | } | |
b331163b A |
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); | |
46f4442e A |
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; | |
729e4ab9 | 319 | } else if ( !uprv_strcmp(key, "h") || !uprv_strcmp(key, "H") ) { |
46f4442e A |
320 | calendarField = UCAL_HOUR; |
321 | } else if ( !uprv_strcmp(key, "m") ) { | |
322 | calendarField = UCAL_MINUTE; | |
323 | } | |
324 | if ( calendarField != UCAL_FIELD_COUNT ) { | |
4388f060 | 325 | setIntervalPatternInternally(skeletonUniStr, calendarField, pattern,status); |
46f4442e A |
326 | } |
327 | } | |
46f4442e | 328 | } |
46f4442e A |
329 | } |
330 | } | |
331 | ures_close(itvDtPtnResource); | |
729e4ab9 | 332 | ures_close(calTypeBundle); |
46f4442e | 333 | ures_close(calBundle); |
4388f060 | 334 | |
46f4442e | 335 | status = U_ZERO_ERROR; |
4388f060 A |
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 ); | |
46f4442e A |
363 | } |
364 | ||
365 | ||
366 | ||
367 | void | |
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 | |
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 | |
406 | DateIntervalInfo::stringNumeric(int32_t fieldWidth, int32_t anotherFieldWidth, | |
407 | char patternLetter) { | |
408 | if ( patternLetter == 'M' ) { | |
729e4ab9 A |
409 | if ( (fieldWidth <= 2 && anotherFieldWidth > 2) || |
410 | (fieldWidth > 2 && anotherFieldWidth <= 2 )) { | |
46f4442e A |
411 | return true; |
412 | } | |
413 | } | |
414 | return false; | |
415 | } | |
416 | ||
417 | ||
418 | ||
419 | const UnicodeString* | |
420 | 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 ) { | |
46f4442e | 469 | copySkeleton = skeleton; |
4388f060 | 470 | copySkeleton.findAndReplace(UnicodeString(CHAR_Z), UnicodeString(CHAR_V)); |
46f4442e A |
471 | inputSkeleton = ©Skeleton; |
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 | ||
b331163b | 486 | int32_t pos = UHASH_FIRST; |
46f4442e A |
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 | |
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; | |
b331163b A |
577 | case UCAL_SECOND: |
578 | index = kIPI_SECOND; | |
579 | break; | |
46f4442e A |
580 | default: |
581 | status = U_ILLEGAL_ARGUMENT_ERROR; | |
582 | } | |
583 | return index; | |
584 | } | |
585 | ||
586 | ||
587 | ||
588 | void | |
589 | DateIntervalInfo::deleteHash(Hashtable* hTable) | |
590 | { | |
591 | if ( hTable == NULL ) { | |
592 | return; | |
593 | } | |
b331163b | 594 | int32_t pos = UHASH_FIRST; |
46f4442e A |
595 | const UHashElement* element = NULL; |
596 | while ( (element = hTable->nextElement(pos)) != NULL ) { | |
46f4442e A |
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 | */ | |
729e4ab9 | 614 | static UBool U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2); |
46f4442e | 615 | |
729e4ab9 A |
616 | static UBool |
617 | U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2) { | |
46f4442e A |
618 | const UnicodeString* pattern1 = (UnicodeString*)val1.pointer; |
619 | const UnicodeString* pattern2 = (UnicodeString*)val2.pointer; | |
620 | UBool ret = TRUE; | |
621 | int8_t i; | |
729e4ab9 | 622 | for ( i = 0; i < DateIntervalInfo::kMaxIntervalPatternIndex && ret == TRUE; ++i ) { |
46f4442e A |
623 | ret = (pattern1[i] == pattern2[i]); |
624 | } | |
625 | return ret; | |
626 | } | |
627 | ||
729e4ab9 | 628 | U_CDECL_END |
46f4442e A |
629 | |
630 | ||
631 | Hashtable* | |
632 | DateIntervalInfo::initHash(UErrorCode& status) { | |
633 | if ( U_FAILURE(status) ) { | |
634 | return NULL; | |
635 | } | |
636 | Hashtable* hTable; | |
729e4ab9 | 637 | if ( (hTable = new Hashtable(FALSE, status)) == NULL ) { |
46f4442e A |
638 | status = U_MEMORY_ALLOCATION_ERROR; |
639 | return NULL; | |
640 | } | |
729e4ab9 A |
641 | if ( U_FAILURE(status) ) { |
642 | delete hTable; | |
643 | return NULL; | |
644 | } | |
645 | hTable->setValueComparator(dtitvinfHashTableValueComparator); | |
46f4442e A |
646 | return hTable; |
647 | } | |
648 | ||
649 | ||
650 | void | |
651 | DateIntervalInfo::copyHash(const Hashtable* source, | |
652 | Hashtable* target, | |
653 | UErrorCode& status) { | |
654 | if ( U_FAILURE(status) ) { | |
655 | return; | |
656 | } | |
b331163b | 657 | int32_t pos = UHASH_FIRST; |
46f4442e A |
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 |