1 /*
2 *******************************************************************************
3 * Copyright (C) 1996-2011, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 *******************************************************************************
6 */
7
8 #include <typeinfo> // for 'typeid' to work
9
10 #include "unicode/utypes.h"
11
12 #if !UCONFIG_NO_FORMATTING
13
14 #include "unicode/ucal.h"
15 #include "unicode/uloc.h"
16 #include "unicode/calendar.h"
17 #include "unicode/timezone.h"
18 #include "unicode/gregocal.h"
19 #include "unicode/simpletz.h"
20 #include "unicode/ustring.h"
21 #include "unicode/strenum.h"
22 #include "cmemory.h"
23 #include "cstring.h"
24 #include "ustrenum.h"
25 #include "uenumimp.h"
26 #include "ulist.h"
27
28 U_NAMESPACE_USE
29
30 static TimeZone*
_createTimeZone(const UChar * zoneID,int32_t len,UErrorCode * ec)31 _createTimeZone(const UChar* zoneID, int32_t len, UErrorCode* ec) {
32 TimeZone* zone = NULL;
33 if (ec!=NULL && U_SUCCESS(*ec)) {
34 // Note that if zoneID is invalid, we get back GMT. This odd
35 // behavior is by design and goes back to the JDK. The only
36 // failure we will see is a memory allocation failure.
37 int32_t l = (len<0 ? u_strlen(zoneID) : len);
38 UnicodeString zoneStrID;
39 zoneStrID.setTo((UBool)(len < 0), zoneID, l); /* temporary read-only alias */
40 zone = TimeZone::createTimeZone(zoneStrID);
41 if (zone == NULL) {
42 *ec = U_MEMORY_ALLOCATION_ERROR;
43 }
44 }
45 return zone;
46 }
47
48 U_CAPI UEnumeration* U_EXPORT2
ucal_openTimeZoneIDEnumeration(USystemTimeZoneType zoneType,const char * region,const int32_t * rawOffset,UErrorCode * ec)49 ucal_openTimeZoneIDEnumeration(USystemTimeZoneType zoneType, const char* region,
50 const int32_t* rawOffset, UErrorCode* ec) {
51 return uenum_openFromStringEnumeration(TimeZone::createTimeZoneIDEnumeration(
52 zoneType, region, rawOffset, *ec), ec);
53 }
54
55 U_CAPI UEnumeration* U_EXPORT2
ucal_openTimeZones(UErrorCode * ec)56 ucal_openTimeZones(UErrorCode* ec) {
57 return uenum_openFromStringEnumeration(TimeZone::createEnumeration(), ec);
58 }
59
60 U_CAPI UEnumeration* U_EXPORT2
ucal_openCountryTimeZones(const char * country,UErrorCode * ec)61 ucal_openCountryTimeZones(const char* country, UErrorCode* ec) {
62 return uenum_openFromStringEnumeration(TimeZone::createEnumeration(country), ec);
63 }
64
65 U_CAPI int32_t U_EXPORT2
ucal_getDefaultTimeZone(UChar * result,int32_t resultCapacity,UErrorCode * ec)66 ucal_getDefaultTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* ec) {
67 int32_t len = 0;
68 if (ec!=NULL && U_SUCCESS(*ec)) {
69 TimeZone* zone = TimeZone::createDefault();
70 if (zone == NULL) {
71 *ec = U_MEMORY_ALLOCATION_ERROR;
72 } else {
73 UnicodeString id;
74 zone->getID(id);
75 delete zone;
76 len = id.extract(result, resultCapacity, *ec);
77 }
78 }
79 return len;
80 }
81
82 U_CAPI void U_EXPORT2
ucal_setDefaultTimeZone(const UChar * zoneID,UErrorCode * ec)83 ucal_setDefaultTimeZone(const UChar* zoneID, UErrorCode* ec) {
84 TimeZone* zone = _createTimeZone(zoneID, -1, ec);
85 if (zone != NULL) {
86 TimeZone::adoptDefault(zone);
87 }
88 }
89
90 U_CAPI int32_t U_EXPORT2
ucal_getDSTSavings(const UChar * zoneID,UErrorCode * ec)91 ucal_getDSTSavings(const UChar* zoneID, UErrorCode* ec) {
92 int32_t result = 0;
93 TimeZone* zone = _createTimeZone(zoneID, -1, ec);
94 if (U_SUCCESS(*ec)) {
95 SimpleTimeZone* stz = dynamic_cast<SimpleTimeZone*>(zone);
96 if (stz != NULL) {
97 result = stz->getDSTSavings();
98 } else {
99 // Since there is no getDSTSavings on TimeZone, we use a
100 // heuristic: Starting with the current time, march
101 // forwards for one year, looking for DST savings.
102 // Stepping by weeks is sufficient.
103 UDate d = Calendar::getNow();
104 for (int32_t i=0; i<53; ++i, d+=U_MILLIS_PER_DAY*7.0) {
105 int32_t raw, dst;
106 zone->getOffset(d, FALSE, raw, dst, *ec);
107 if (U_FAILURE(*ec)) {
108 break;
109 } else if (dst != 0) {
110 result = dst;
111 break;
112 }
113 }
114 }
115 }
116 delete zone;
117 return result;
118 }
119
120 U_CAPI UDate U_EXPORT2
ucal_getNow()121 ucal_getNow()
122 {
123
124 return Calendar::getNow();
125 }
126
127 #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
128
129 U_CAPI UCalendar* U_EXPORT2
ucal_open(const UChar * zoneID,int32_t len,const char * locale,UCalendarType caltype,UErrorCode * status)130 ucal_open( const UChar* zoneID,
131 int32_t len,
132 const char* locale,
133 UCalendarType caltype,
134 UErrorCode* status)
135 {
136
137 if(U_FAILURE(*status)) return 0;
138
139 TimeZone* zone = (zoneID==NULL) ? TimeZone::createDefault()
140 : _createTimeZone(zoneID, len, status);
141
142 if (U_FAILURE(*status)) {
143 return NULL;
144 }
145
146 if ( caltype == UCAL_GREGORIAN ) {
147 char localeBuf[ULOC_LOCALE_IDENTIFIER_CAPACITY];
148 if ( locale == NULL ) {
149 locale = uloc_getDefault();
150 }
151 uprv_strncpy(localeBuf, locale, ULOC_LOCALE_IDENTIFIER_CAPACITY);
152 uloc_setKeywordValue("calendar", "gregorian", localeBuf, ULOC_LOCALE_IDENTIFIER_CAPACITY, status);
153 if (U_FAILURE(*status)) {
154 return NULL;
155 }
156 return (UCalendar*)Calendar::createInstance(zone, Locale(localeBuf), *status);
157 }
158 return (UCalendar*)Calendar::createInstance(zone, Locale(locale), *status);
159 }
160
161 U_CAPI void U_EXPORT2
ucal_close(UCalendar * cal)162 ucal_close(UCalendar *cal)
163 {
164
165 delete (Calendar*) cal;
166 }
167
168 U_CAPI UCalendar* U_EXPORT2
ucal_clone(const UCalendar * cal,UErrorCode * status)169 ucal_clone(const UCalendar* cal,
170 UErrorCode* status)
171 {
172 if(U_FAILURE(*status)) return 0;
173
174 Calendar* res = ((Calendar*)cal)->clone();
175
176 if(res == 0) {
177 *status = U_MEMORY_ALLOCATION_ERROR;
178 return 0;
179 }
180
181 return (UCalendar*) res;
182 }
183
184 U_CAPI void U_EXPORT2
ucal_setTimeZone(UCalendar * cal,const UChar * zoneID,int32_t len,UErrorCode * status)185 ucal_setTimeZone( UCalendar* cal,
186 const UChar* zoneID,
187 int32_t len,
188 UErrorCode *status)
189 {
190
191 if(U_FAILURE(*status))
192 return;
193
194 TimeZone* zone = (zoneID==NULL) ? TimeZone::createDefault()
195 : _createTimeZone(zoneID, len, status);
196
197 if (zone != NULL) {
198 ((Calendar*)cal)->adoptTimeZone(zone);
199 }
200 }
201
202 U_CAPI int32_t U_EXPORT2
ucal_getTimeZoneDisplayName(const UCalendar * cal,UCalendarDisplayNameType type,const char * locale,UChar * result,int32_t resultLength,UErrorCode * status)203 ucal_getTimeZoneDisplayName(const UCalendar* cal,
204 UCalendarDisplayNameType type,
205 const char *locale,
206 UChar* result,
207 int32_t resultLength,
208 UErrorCode* status)
209 {
210
211 if(U_FAILURE(*status)) return -1;
212
213 const TimeZone& tz = ((Calendar*)cal)->getTimeZone();
214 UnicodeString id;
215 if(!(result==NULL && resultLength==0)) {
216 // NULL destination for pure preflighting: empty dummy string
217 // otherwise, alias the destination buffer
218 id.setTo(result, 0, resultLength);
219 }
220
221 switch(type) {
222 case UCAL_STANDARD:
223 tz.getDisplayName(FALSE, TimeZone::LONG, Locale(locale), id);
224 break;
225
226 case UCAL_SHORT_STANDARD:
227 tz.getDisplayName(FALSE, TimeZone::SHORT, Locale(locale), id);
228 break;
229
230 case UCAL_DST:
231 tz.getDisplayName(TRUE, TimeZone::LONG, Locale(locale), id);
232 break;
233
234 case UCAL_SHORT_DST:
235 tz.getDisplayName(TRUE, TimeZone::SHORT, Locale(locale), id);
236 break;
237 }
238
239 return id.extract(result, resultLength, *status);
240 }
241
242 U_CAPI UBool U_EXPORT2
ucal_inDaylightTime(const UCalendar * cal,UErrorCode * status)243 ucal_inDaylightTime( const UCalendar* cal,
244 UErrorCode* status )
245 {
246
247 if(U_FAILURE(*status)) return (UBool) -1;
248 return ((Calendar*)cal)->inDaylightTime(*status);
249 }
250
251 U_CAPI void U_EXPORT2
ucal_setGregorianChange(UCalendar * cal,UDate date,UErrorCode * pErrorCode)252 ucal_setGregorianChange(UCalendar *cal, UDate date, UErrorCode *pErrorCode) {
253 if(U_FAILURE(*pErrorCode)) {
254 return;
255 }
256 Calendar *cpp_cal = (Calendar *)cal;
257 GregorianCalendar *gregocal = dynamic_cast<GregorianCalendar *>(cpp_cal);
258 // Not if(gregocal == NULL) {
259 // because we really want to work only with a GregorianCalendar, not with
260 // its subclasses like BuddhistCalendar.
261 // BEGIN android-added.
262 // See ICU ticket#9047.
263 if (cpp_cal == NULL) {
264 // We normally don't check "this" pointers for NULL, but this here avoids
265 // compiler-generated exception-throwing code in case cal == NULL.
266 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
267 return;
268 }
269 // END android-added
270 if(typeid(*cpp_cal) != typeid(GregorianCalendar)) {
271 *pErrorCode = U_UNSUPPORTED_ERROR;
272 return;
273 }
274 gregocal->setGregorianChange(date, *pErrorCode);
275 }
276
277 U_CAPI UDate U_EXPORT2
ucal_getGregorianChange(const UCalendar * cal,UErrorCode * pErrorCode)278 ucal_getGregorianChange(const UCalendar *cal, UErrorCode *pErrorCode) {
279 if(U_FAILURE(*pErrorCode)) {
280 return (UDate)0;
281 }
282 const Calendar *cpp_cal = (const Calendar *)cal;
283 const GregorianCalendar *gregocal = dynamic_cast<const GregorianCalendar *>(cpp_cal);
284 // Not if(gregocal == NULL) {
285 // see comments in ucal_setGregorianChange().
286 // BEGIN android-added.
287 // See ICU ticket#9047.
288 if (cpp_cal == NULL) {
289 // We normally don't check "this" pointers for NULL, but this here avoids
290 // compiler-generated exception-throwing code in case cal == NULL.
291 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
292 return (UDate)0;
293 }
294 // END android-added
295 if(typeid(*cpp_cal) != typeid(GregorianCalendar)) {
296 *pErrorCode = U_UNSUPPORTED_ERROR;
297 return (UDate)0;
298 }
299 return gregocal->getGregorianChange();
300 }
301
302 U_CAPI int32_t U_EXPORT2
ucal_getAttribute(const UCalendar * cal,UCalendarAttribute attr)303 ucal_getAttribute( const UCalendar* cal,
304 UCalendarAttribute attr)
305 {
306
307 switch(attr) {
308 case UCAL_LENIENT:
309 return ((Calendar*)cal)->isLenient();
310
311 case UCAL_FIRST_DAY_OF_WEEK:
312 return ((Calendar*)cal)->getFirstDayOfWeek();
313
314 case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK:
315 return ((Calendar*)cal)->getMinimalDaysInFirstWeek();
316
317 default:
318 break;
319 }
320 return -1;
321 }
322
323 U_CAPI void U_EXPORT2
ucal_setAttribute(UCalendar * cal,UCalendarAttribute attr,int32_t newValue)324 ucal_setAttribute( UCalendar* cal,
325 UCalendarAttribute attr,
326 int32_t newValue)
327 {
328
329 switch(attr) {
330 case UCAL_LENIENT:
331 ((Calendar*)cal)->setLenient((UBool)newValue);
332 break;
333
334 case UCAL_FIRST_DAY_OF_WEEK:
335 ((Calendar*)cal)->setFirstDayOfWeek((UCalendarDaysOfWeek)newValue);
336 break;
337
338 case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK:
339 ((Calendar*)cal)->setMinimalDaysInFirstWeek((uint8_t)newValue);
340 break;
341 }
342 }
343
344 U_CAPI const char* U_EXPORT2
ucal_getAvailable(int32_t index)345 ucal_getAvailable(int32_t index)
346 {
347
348 return uloc_getAvailable(index);
349 }
350
351 U_CAPI int32_t U_EXPORT2
ucal_countAvailable()352 ucal_countAvailable()
353 {
354
355 return uloc_countAvailable();
356 }
357
358 U_CAPI UDate U_EXPORT2
ucal_getMillis(const UCalendar * cal,UErrorCode * status)359 ucal_getMillis( const UCalendar* cal,
360 UErrorCode* status)
361 {
362
363 if(U_FAILURE(*status)) return (UDate) 0;
364
365 return ((Calendar*)cal)->getTime(*status);
366 }
367
368 U_CAPI void U_EXPORT2
ucal_setMillis(UCalendar * cal,UDate dateTime,UErrorCode * status)369 ucal_setMillis( UCalendar* cal,
370 UDate dateTime,
371 UErrorCode* status )
372 {
373 if(U_FAILURE(*status)) return;
374
375 ((Calendar*)cal)->setTime(dateTime, *status);
376 }
377
378 // TBD: why does this take an UErrorCode?
379 U_CAPI void U_EXPORT2
ucal_setDate(UCalendar * cal,int32_t year,int32_t month,int32_t date,UErrorCode * status)380 ucal_setDate( UCalendar* cal,
381 int32_t year,
382 int32_t month,
383 int32_t date,
384 UErrorCode *status)
385 {
386
387 if(U_FAILURE(*status)) return;
388
389 ((Calendar*)cal)->set(year, month, date);
390 }
391
392 // TBD: why does this take an UErrorCode?
393 U_CAPI void U_EXPORT2
ucal_setDateTime(UCalendar * cal,int32_t year,int32_t month,int32_t date,int32_t hour,int32_t minute,int32_t second,UErrorCode * status)394 ucal_setDateTime( UCalendar* cal,
395 int32_t year,
396 int32_t month,
397 int32_t date,
398 int32_t hour,
399 int32_t minute,
400 int32_t second,
401 UErrorCode *status)
402 {
403 if(U_FAILURE(*status)) return;
404
405 ((Calendar*)cal)->set(year, month, date, hour, minute, second);
406 }
407
408 U_CAPI UBool U_EXPORT2
ucal_equivalentTo(const UCalendar * cal1,const UCalendar * cal2)409 ucal_equivalentTo( const UCalendar* cal1,
410 const UCalendar* cal2)
411 {
412
413 return ((Calendar*)cal1)->isEquivalentTo(*((Calendar*)cal2));
414 }
415
416 U_CAPI void U_EXPORT2
ucal_add(UCalendar * cal,UCalendarDateFields field,int32_t amount,UErrorCode * status)417 ucal_add( UCalendar* cal,
418 UCalendarDateFields field,
419 int32_t amount,
420 UErrorCode* status)
421 {
422
423 if(U_FAILURE(*status)) return;
424
425 ((Calendar*)cal)->add(field, amount, *status);
426 }
427
428 U_CAPI void U_EXPORT2
ucal_roll(UCalendar * cal,UCalendarDateFields field,int32_t amount,UErrorCode * status)429 ucal_roll( UCalendar* cal,
430 UCalendarDateFields field,
431 int32_t amount,
432 UErrorCode* status)
433 {
434
435 if(U_FAILURE(*status)) return;
436
437 ((Calendar*)cal)->roll(field, amount, *status);
438 }
439
440 U_CAPI int32_t U_EXPORT2
ucal_get(const UCalendar * cal,UCalendarDateFields field,UErrorCode * status)441 ucal_get( const UCalendar* cal,
442 UCalendarDateFields field,
443 UErrorCode* status )
444 {
445
446 if(U_FAILURE(*status)) return -1;
447
448 return ((Calendar*)cal)->get(field, *status);
449 }
450
451 U_CAPI void U_EXPORT2
ucal_set(UCalendar * cal,UCalendarDateFields field,int32_t value)452 ucal_set( UCalendar* cal,
453 UCalendarDateFields field,
454 int32_t value)
455 {
456
457 ((Calendar*)cal)->set(field, value);
458 }
459
460 U_CAPI UBool U_EXPORT2
ucal_isSet(const UCalendar * cal,UCalendarDateFields field)461 ucal_isSet( const UCalendar* cal,
462 UCalendarDateFields field)
463 {
464
465 return ((Calendar*)cal)->isSet(field);
466 }
467
468 U_CAPI void U_EXPORT2
ucal_clearField(UCalendar * cal,UCalendarDateFields field)469 ucal_clearField( UCalendar* cal,
470 UCalendarDateFields field)
471 {
472
473 ((Calendar*)cal)->clear(field);
474 }
475
476 U_CAPI void U_EXPORT2
ucal_clear(UCalendar * calendar)477 ucal_clear(UCalendar* calendar)
478 {
479
480 ((Calendar*)calendar)->clear();
481 }
482
483 U_CAPI int32_t U_EXPORT2
ucal_getLimit(const UCalendar * cal,UCalendarDateFields field,UCalendarLimitType type,UErrorCode * status)484 ucal_getLimit( const UCalendar* cal,
485 UCalendarDateFields field,
486 UCalendarLimitType type,
487 UErrorCode *status)
488 {
489
490 if(status==0 || U_FAILURE(*status)) {
491 return -1;
492 }
493
494 switch(type) {
495 case UCAL_MINIMUM:
496 return ((Calendar*)cal)->getMinimum(field);
497
498 case UCAL_MAXIMUM:
499 return ((Calendar*)cal)->getMaximum(field);
500
501 case UCAL_GREATEST_MINIMUM:
502 return ((Calendar*)cal)->getGreatestMinimum(field);
503
504 case UCAL_LEAST_MAXIMUM:
505 return ((Calendar*)cal)->getLeastMaximum(field);
506
507 case UCAL_ACTUAL_MINIMUM:
508 return ((Calendar*)cal)->getActualMinimum(field,
509 *status);
510
511 case UCAL_ACTUAL_MAXIMUM:
512 return ((Calendar*)cal)->getActualMaximum(field,
513 *status);
514
515 default:
516 break;
517 }
518 return -1;
519 }
520
521 U_CAPI const char * U_EXPORT2
ucal_getLocaleByType(const UCalendar * cal,ULocDataLocaleType type,UErrorCode * status)522 ucal_getLocaleByType(const UCalendar *cal, ULocDataLocaleType type, UErrorCode* status)
523 {
524 if (cal == NULL) {
525 if (U_SUCCESS(*status)) {
526 *status = U_ILLEGAL_ARGUMENT_ERROR;
527 }
528 return NULL;
529 }
530 return ((Calendar*)cal)->getLocaleID(type, *status);
531 }
532
533 U_CAPI const char * U_EXPORT2
ucal_getTZDataVersion(UErrorCode * status)534 ucal_getTZDataVersion(UErrorCode* status)
535 {
536 return TimeZone::getTZDataVersion(*status);
537 }
538
539 U_CAPI int32_t U_EXPORT2
ucal_getCanonicalTimeZoneID(const UChar * id,int32_t len,UChar * result,int32_t resultCapacity,UBool * isSystemID,UErrorCode * status)540 ucal_getCanonicalTimeZoneID(const UChar* id, int32_t len,
541 UChar* result, int32_t resultCapacity, UBool *isSystemID, UErrorCode* status) {
542 if(status == 0 || U_FAILURE(*status)) {
543 return 0;
544 }
545 if (isSystemID) {
546 *isSystemID = FALSE;
547 }
548 if (id == 0 || len == 0 || result == 0 || resultCapacity <= 0) {
549 *status = U_ILLEGAL_ARGUMENT_ERROR;
550 return 0;
551 }
552 int32_t reslen = 0;
553 UnicodeString canonical;
554 UBool systemID = FALSE;
555 TimeZone::getCanonicalID(UnicodeString(id, len), canonical, systemID, *status);
556 if (U_SUCCESS(*status)) {
557 if (isSystemID) {
558 *isSystemID = systemID;
559 }
560 reslen = canonical.extract(result, resultCapacity, *status);
561 }
562 return reslen;
563 }
564
565 U_CAPI const char * U_EXPORT2
ucal_getType(const UCalendar * cal,UErrorCode * status)566 ucal_getType(const UCalendar *cal, UErrorCode* status)
567 {
568 if (U_FAILURE(*status)) {
569 return NULL;
570 }
571 return ((Calendar*)cal)->getType();
572 }
573
574 U_CAPI UCalendarWeekdayType U_EXPORT2
ucal_getDayOfWeekType(const UCalendar * cal,UCalendarDaysOfWeek dayOfWeek,UErrorCode * status)575 ucal_getDayOfWeekType(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode* status)
576 {
577 if (U_FAILURE(*status)) {
578 return UCAL_WEEKDAY;
579 }
580 return ((Calendar*)cal)->getDayOfWeekType(dayOfWeek, *status);
581 }
582
583 U_CAPI int32_t U_EXPORT2
ucal_getWeekendTransition(const UCalendar * cal,UCalendarDaysOfWeek dayOfWeek,UErrorCode * status)584 ucal_getWeekendTransition(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode *status)
585 {
586 if (U_FAILURE(*status)) {
587 return 0;
588 }
589 return ((Calendar*)cal)->getWeekendTransition(dayOfWeek, *status);
590 }
591
592 U_CAPI UBool U_EXPORT2
ucal_isWeekend(const UCalendar * cal,UDate date,UErrorCode * status)593 ucal_isWeekend(const UCalendar *cal, UDate date, UErrorCode *status)
594 {
595 if (U_FAILURE(*status)) {
596 return FALSE;
597 }
598 return ((Calendar*)cal)->isWeekend(date, *status);
599 }
600
601 U_CAPI int32_t U_EXPORT2
ucal_getFieldDifference(UCalendar * cal,UDate target,UCalendarDateFields field,UErrorCode * status)602 ucal_getFieldDifference(UCalendar* cal, UDate target,
603 UCalendarDateFields field,
604 UErrorCode* status )
605 {
606 if (U_FAILURE(*status)) {
607 return 0;
608 }
609 return ((Calendar*)cal)->fieldDifference(target, field, *status);
610 }
611
612
613 static const UEnumeration defaultKeywordValues = {
614 NULL,
615 NULL,
616 ulist_close_keyword_values_iterator,
617 ulist_count_keyword_values,
618 uenum_unextDefault,
619 ulist_next_keyword_value,
620 ulist_reset_keyword_values_iterator
621 };
622
623 static const char * const CAL_TYPES[] = {
624 "gregorian",
625 "japanese",
626 "buddhist",
627 "roc",
628 "persian",
629 "islamic-civil",
630 "islamic",
631 "hebrew",
632 "chinese",
633 "indian",
634 "coptic",
635 "ethiopic",
636 "ethiopic-amete-alem",
637 NULL
638 };
639
640 U_CAPI UEnumeration* U_EXPORT2
ucal_getKeywordValuesForLocale(const char *,const char * locale,UBool commonlyUsed,UErrorCode * status)641 ucal_getKeywordValuesForLocale(const char * /* key */, const char* locale, UBool commonlyUsed, UErrorCode *status) {
642 // Resolve region
643 char prefRegion[ULOC_FULLNAME_CAPACITY] = "";
644 int32_t prefRegionLength = 0;
645 prefRegionLength = uloc_getCountry(locale, prefRegion, sizeof(prefRegion), status);
646 if (prefRegionLength == 0) {
647 char loc[ULOC_FULLNAME_CAPACITY] = "";
648 int32_t locLength = 0;
649 locLength = uloc_addLikelySubtags(locale, loc, sizeof(loc), status);
650
651 prefRegionLength = uloc_getCountry(loc, prefRegion, sizeof(prefRegion), status);
652 }
653
654 // Read preferred calendar values from supplementalData calendarPreference
655 UResourceBundle *rb = ures_openDirect(NULL, "supplementalData", status);
656 ures_getByKey(rb, "calendarPreferenceData", rb, status);
657 UResourceBundle *order = ures_getByKey(rb, prefRegion, NULL, status);
658 if (*status == U_MISSING_RESOURCE_ERROR && rb != NULL) {
659 *status = U_ZERO_ERROR;
660 order = ures_getByKey(rb, "001", NULL, status);
661 }
662
663 // Create a list of calendar type strings
664 UList *values = NULL;
665 if (U_SUCCESS(*status)) {
666 values = ulist_createEmptyList(status);
667 if (U_SUCCESS(*status)) {
668 for (int i = 0; i < ures_getSize(order); i++) {
669 int32_t len;
670 const UChar *type = ures_getStringByIndex(order, i, &len, status);
671 char *caltype = (char*)uprv_malloc(len + 1);
672 if (caltype == NULL) {
673 *status = U_MEMORY_ALLOCATION_ERROR;
674 break;
675 }
676 u_UCharsToChars(type, caltype, len);
677 *(caltype + len) = 0;
678
679 ulist_addItemEndList(values, caltype, TRUE, status);
680 if (U_FAILURE(*status)) {
681 break;
682 }
683 }
684
685 if (U_SUCCESS(*status) && !commonlyUsed) {
686 // If not commonlyUsed, add other available values
687 for (int32_t i = 0; CAL_TYPES[i] != NULL; i++) {
688 if (!ulist_containsString(values, CAL_TYPES[i], (int32_t)uprv_strlen(CAL_TYPES[i]))) {
689 ulist_addItemEndList(values, CAL_TYPES[i], FALSE, status);
690 if (U_FAILURE(*status)) {
691 break;
692 }
693 }
694 }
695 }
696 if (U_FAILURE(*status)) {
697 ulist_deleteList(values);
698 values = NULL;
699 }
700 }
701 }
702
703 ures_close(order);
704 ures_close(rb);
705
706 if (U_FAILURE(*status) || values == NULL) {
707 return NULL;
708 }
709
710 // Create string enumeration
711 UEnumeration *en = (UEnumeration*)uprv_malloc(sizeof(UEnumeration));
712 if (en == NULL) {
713 *status = U_MEMORY_ALLOCATION_ERROR;
714 ulist_deleteList(values);
715 return NULL;
716 }
717 ulist_resetList(values);
718 memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
719 en->context = values;
720 return en;
721 }
722
723 #endif /* #if !UCONFIG_NO_FORMATTING */
724