]>
Commit | Line | Data |
---|---|---|
46f4442e | 1 | /******************************************************************************* |
4388f060 | 2 | * Copyright (C) 2008-2012, 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; | |
729e4ab9 | 226 | Hashtable skeletonSet(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); | |
280 | if ( skeletonSet.geti(skeletonUniStr) == 1 ) { | |
46f4442e A |
281 | continue; |
282 | } | |
4388f060 | 283 | skeletonSet.puti(skeletonUniStr, 1, status); |
46f4442e | 284 | if ( uprv_strcmp(skeleton, gFallbackPatternTag) == 0 ) { |
46f4442e A |
285 | continue; // fallback |
286 | } | |
4388f060 A |
287 | |
288 | LocalUResourceBundlePointer intervalPatterns(ures_getByKey( | |
289 | itvDtPtnResource, skeleton, NULL, &status)); | |
290 | ||
46f4442e | 291 | if ( U_FAILURE(status) ) { |
46f4442e A |
292 | break; |
293 | } | |
294 | if ( intervalPatterns == NULL ) { | |
46f4442e A |
295 | continue; |
296 | } | |
4388f060 | 297 | |
46f4442e | 298 | const char* key; |
4388f060 | 299 | int32_t ptnNum = ures_getSize(intervalPatterns.getAlias()); |
46f4442e A |
300 | int32_t ptnIndex; |
301 | for ( ptnIndex = 0; ptnIndex < ptnNum; ++ptnIndex ) { | |
4388f060 A |
302 | UnicodeString pattern = |
303 | ures_getNextUnicodeString(intervalPatterns.getAlias(), &key, &status); | |
46f4442e A |
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; | |
729e4ab9 | 317 | } else if ( !uprv_strcmp(key, "h") || !uprv_strcmp(key, "H") ) { |
46f4442e A |
318 | calendarField = UCAL_HOUR; |
319 | } else if ( !uprv_strcmp(key, "m") ) { | |
320 | calendarField = UCAL_MINUTE; | |
321 | } | |
322 | if ( calendarField != UCAL_FIELD_COUNT ) { | |
4388f060 | 323 | setIntervalPatternInternally(skeletonUniStr, calendarField, pattern,status); |
46f4442e A |
324 | } |
325 | } | |
46f4442e | 326 | } |
46f4442e A |
327 | } |
328 | } | |
329 | ures_close(itvDtPtnResource); | |
729e4ab9 | 330 | ures_close(calTypeBundle); |
46f4442e | 331 | ures_close(calBundle); |
4388f060 | 332 | |
46f4442e | 333 | status = U_ZERO_ERROR; |
4388f060 A |
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 ); | |
46f4442e A |
361 | } |
362 | ||
363 | ||
364 | ||
365 | void | |
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 | |
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 | |
404 | DateIntervalInfo::stringNumeric(int32_t fieldWidth, int32_t anotherFieldWidth, | |
405 | char patternLetter) { | |
406 | if ( patternLetter == 'M' ) { | |
729e4ab9 A |
407 | if ( (fieldWidth <= 2 && anotherFieldWidth > 2) || |
408 | (fieldWidth > 2 && anotherFieldWidth <= 2 )) { | |
46f4442e A |
409 | return true; |
410 | } | |
411 | } | |
412 | return false; | |
413 | } | |
414 | ||
415 | ||
416 | ||
417 | const UnicodeString* | |
418 | 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 ) { | |
46f4442e | 467 | copySkeleton = skeleton; |
4388f060 | 468 | copySkeleton.findAndReplace(UnicodeString(CHAR_Z), UnicodeString(CHAR_V)); |
46f4442e A |
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 | |
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 | |
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 ) { | |
46f4442e A |
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 | */ | |
729e4ab9 | 609 | static UBool U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2); |
46f4442e | 610 | |
729e4ab9 A |
611 | static UBool |
612 | U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2) { | |
46f4442e A |
613 | const UnicodeString* pattern1 = (UnicodeString*)val1.pointer; |
614 | const UnicodeString* pattern2 = (UnicodeString*)val2.pointer; | |
615 | UBool ret = TRUE; | |
616 | int8_t i; | |
729e4ab9 | 617 | for ( i = 0; i < DateIntervalInfo::kMaxIntervalPatternIndex && ret == TRUE; ++i ) { |
46f4442e A |
618 | ret = (pattern1[i] == pattern2[i]); |
619 | } | |
620 | return ret; | |
621 | } | |
622 | ||
729e4ab9 | 623 | U_CDECL_END |
46f4442e A |
624 | |
625 | ||
626 | Hashtable* | |
627 | DateIntervalInfo::initHash(UErrorCode& status) { | |
628 | if ( U_FAILURE(status) ) { | |
629 | return NULL; | |
630 | } | |
631 | Hashtable* hTable; | |
729e4ab9 | 632 | if ( (hTable = new Hashtable(FALSE, status)) == NULL ) { |
46f4442e A |
633 | status = U_MEMORY_ALLOCATION_ERROR; |
634 | return NULL; | |
635 | } | |
729e4ab9 A |
636 | if ( U_FAILURE(status) ) { |
637 | delete hTable; | |
638 | return NULL; | |
639 | } | |
640 | hTable->setValueComparator(dtitvinfHashTableValueComparator); | |
46f4442e A |
641 | return hTable; |
642 | } | |
643 | ||
644 | ||
645 | void | |
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 |