From 4c64b92b4adb277d7e88cdacbc71b2545071847a Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Wed, 14 Oct 2015 12:30:37 -0700 Subject: Remove use of ICU C++ Calendar class We would like to be able to link against versions of ICU installed as a "operating system level library" which means we can't take a dependency on any C++ APIs. This change moves away from icu::Calendar in favor of UCalendar. I also introduce a small helper template to manage the lifetime of ICU resources. --- .../System.Globalization.Native/calendarData.cpp | 48 ++++++++++--------- src/corefx/System.Globalization.Native/holders.h | 55 ++++++++++++++++++++++ .../localeNumberData.cpp | 13 +++-- 3 files changed, 90 insertions(+), 26 deletions(-) create mode 100644 src/corefx/System.Globalization.Native/holders.h diff --git a/src/corefx/System.Globalization.Native/calendarData.cpp b/src/corefx/System.Globalization.Native/calendarData.cpp index 98c3127549..21808f7053 100644 --- a/src/corefx/System.Globalization.Native/calendarData.cpp +++ b/src/corefx/System.Globalization.Native/calendarData.cpp @@ -7,6 +7,7 @@ #include #include "locale.hpp" +#include "holders.h" #include #include @@ -208,13 +209,13 @@ extern "C" int32_t GetCalendars(const UChar* localeName, CalendarId* calendars, return 0; UErrorCode err = U_ZERO_ERROR; - LocalPointer stringEnumerator( - Calendar::getKeywordValuesForLocale("calendar", locale, TRUE, err)); + UEnumeration* pEnum = ucal_getKeywordValuesForLocale("calendar", locale.getName(), TRUE, &err); + UEnumerationHolder enumHolder(pEnum, err); - if (stringEnumerator.isNull() || U_FAILURE(err)) + if (U_FAILURE(err)) return 0; - int stringEnumeratorCount = stringEnumerator->count(err); + int stringEnumeratorCount = uenum_count(pEnum, &err); if (U_FAILURE(err)) return 0; @@ -222,7 +223,7 @@ extern "C" int32_t GetCalendars(const UChar* localeName, CalendarId* calendars, for (int i = 0; i < stringEnumeratorCount && calendarsReturned < calendarsCapacity; i++) { int32_t calendarNameLength = 0; - const char* calendarName = stringEnumerator->next(&calendarNameLength, err); + const char* calendarName = uenum_next(pEnum, &calendarNameLength, &err); if (U_SUCCESS(err)) { CalendarId calendarId = GetCalendarId(calendarName); @@ -558,13 +559,15 @@ Gets the latest era in the Japanese calendar. extern "C" int32_t GetLatestJapaneseEra() { UErrorCode err = U_ZERO_ERROR; - Locale japaneseLocale(JAPANESE_LOCALE_AND_CALENDAR); - LocalPointer calendar(Calendar::createInstance(japaneseLocale, err)); + UCalendar* pCal = ucal_open(nullptr, 0, JAPANESE_LOCALE_AND_CALENDAR, UCAL_TRADITIONAL, &err); + UCalendarHolder calHolder(pCal, err); if (U_FAILURE(err)) return 0; - return calendar->getMaximum(UCAL_ERA); + int32_t ret = ucal_getLimit(pCal, UCAL_ERA, UCAL_MAXIMUM, &err); + + return U_SUCCESS(err) ? ret : 0; } /* @@ -580,27 +583,28 @@ extern "C" int32_t GetJapaneseEraStartDate(int32_t era, int32_t* startYear, int3 *startDay = -1; UErrorCode err = U_ZERO_ERROR; - Locale japaneseLocale(JAPANESE_LOCALE_AND_CALENDAR); - LocalPointer calendar(Calendar::createInstance(japaneseLocale, err)); + UCalendar* pCal = ucal_open(nullptr, 0, JAPANESE_LOCALE_AND_CALENDAR, UCAL_TRADITIONAL, &err); + UCalendarHolder calHolder(pCal, err); + if (U_FAILURE(err)) return false; - calendar->set(UCAL_ERA, era); - calendar->set(UCAL_YEAR, 1); + ucal_set(pCal, UCAL_ERA, era); + ucal_set(pCal, UCAL_YEAR, 1); // UCAL_EXTENDED_YEAR is the gregorian year for the JapaneseCalendar - *startYear = calendar->get(UCAL_EXTENDED_YEAR, err); + *startYear = ucal_get(pCal, UCAL_EXTENDED_YEAR, &err); if (U_FAILURE(err)) return false; // set the date to Jan 1 - calendar->set(UCAL_MONTH, 0); - calendar->set(UCAL_DATE, 1); + ucal_set(pCal, UCAL_MONTH, 0); + ucal_set(pCal, UCAL_DATE, 1); int32_t currentEra; for (int i = 0; i <= 12; i++) { - currentEra = calendar->get(UCAL_ERA, err); + currentEra = ucal_get(pCal, UCAL_ERA, &err); if (U_FAILURE(err)) return false; @@ -609,27 +613,27 @@ extern "C" int32_t GetJapaneseEraStartDate(int32_t era, int32_t* startYear, int3 for (int i = 0; i < 31; i++) { // subtract 1 day at a time until we get out of the specified Era - calendar->add(Calendar::DATE, -1, err); + ucal_add(pCal, UCAL_DATE, -1, &err); if (U_FAILURE(err)) return false; - currentEra = calendar->get(UCAL_ERA, err); + currentEra = ucal_get(pCal, UCAL_ERA, &err); if (U_FAILURE(err)) return false; if (currentEra != era) { // add back 1 day to get back into the specified Era - calendar->add(UCAL_DATE, 1, err); + ucal_add(pCal, UCAL_DATE, 1, &err); if (U_FAILURE(err)) return false; *startMonth = - calendar->get(UCAL_MONTH, err) + 1; // ICU Calendar months are 0-based, but .NET is 1-based + ucal_get(pCal, UCAL_MONTH, &err) + 1; // ICU Calendar months are 0-based, but .NET is 1-based if (U_FAILURE(err)) return false; - *startDay = calendar->get(UCAL_DATE, err); + *startDay = ucal_get(pCal, UCAL_DATE, &err); if (U_FAILURE(err)) return false; @@ -639,7 +643,7 @@ extern "C" int32_t GetJapaneseEraStartDate(int32_t era, int32_t* startYear, int3 } // add 1 month at a time until we get into the specified Era - calendar->add(UCAL_MONTH, 1, err); + ucal_add(pCal, UCAL_MONTH, 1, &err); if (U_FAILURE(err)) return false; } diff --git a/src/corefx/System.Globalization.Native/holders.h b/src/corefx/System.Globalization.Native/holders.h new file mode 100644 index 0000000000..ea757fc30d --- /dev/null +++ b/src/corefx/System.Globalization.Native/holders.h @@ -0,0 +1,55 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "unicode/ucal.h" +#include "unicode/uenum.h" + +// IcuHolder is a template that can manage the lifetime of a raw pointer to ensure that it is cleaned up at the correct +// time. The general usage pattern is to aquire some ICU resource via an _open call, then construct a holder using the +// pointer and UErrorCode to manage the lifetime. When the holder goes out of scope, the coresponding close method is +// called on the pointer. +template +class IcuHolder +{ + public: + IcuHolder(T* p, UErrorCode err) + { + m_p = U_SUCCESS(err) ? p : nullptr; + } + + ~IcuHolder() + { + if (m_p != nullptr) + { + Closer()(m_p); + } + } + + private: + T* m_p; + IcuHolder(const IcuHolder&); + IcuHolder operator=(const IcuHolder&); +}; + +struct UCalendarCloser +{ + public: + void operator()(UCalendar* pCal) const + { + ucal_close(pCal); + } +}; + +struct UEnumerationCloser +{ + public: + void operator()(UEnumeration* pEnum) const + { + uenum_close(pEnum); + } +}; + +typedef IcuHolder UCalendarHolder; +typedef IcuHolder UEnumerationHolder; diff --git a/src/corefx/System.Globalization.Native/localeNumberData.cpp b/src/corefx/System.Globalization.Native/localeNumberData.cpp index 01ace2977c..a73bdc1188 100644 --- a/src/corefx/System.Globalization.Native/localeNumberData.cpp +++ b/src/corefx/System.Globalization.Native/localeNumberData.cpp @@ -8,6 +8,7 @@ #include #include "locale.hpp" +#include "holders.h" #include "unicode/calendar.h" #include "unicode/decimfmt.h" @@ -442,11 +443,13 @@ extern "C" int32_t GetLocaleInfoInt(const UChar* localeName, LocaleNumberData lo case FirstWeekOfYear: { // corresponds to DateTimeFormat.CalendarWeekRule - LocalPointer calendar(Calendar::createInstance(locale, status)); + UCalendar* pCal = ucal_open(nullptr, 0, locale.getName(), UCAL_TRADITIONAL, &status); + UCalendarHolder calHolder(pCal, status); + if (U_SUCCESS(status)) { // values correspond to LOCALE_IFIRSTWEEKOFYEAR - int minDaysInWeek = calendar->getMinimalDaysInFirstWeek(); + int minDaysInWeek = ucal_getAttribute(pCal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK); if (minDaysInWeek == 1) { *value = CalendarWeekRule::FirstDay; @@ -483,10 +486,12 @@ extern "C" int32_t GetLocaleInfoInt(const UChar* localeName, LocaleNumberData lo } case FirstDayofWeek: { - LocalPointer pcalendar(Calendar::createInstance(locale, status)); + UCalendar* pCal = ucal_open(nullptr, 0, locale.getName(), UCAL_TRADITIONAL, &status); + UCalendarHolder calHolder(pCal, status); + if (U_SUCCESS(status)) { - *value = pcalendar->getFirstDayOfWeek(status) - 1; // .NET is 0-based and ICU is 1-based + *value = ucal_getAttribute(pCal, UCAL_FIRST_DAY_OF_WEEK) - 1; // .NET is 0-based and ICU is 1-based } break; } -- cgit v1.2.3 From 894c6cc94929b2ea842c1b256678ae97855da961 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Wed, 14 Oct 2015 15:45:03 -0700 Subject: Convert DateTimePatternGenerator usage to C Part of the effort to remove our usage of C++ ICU APIs. The major issue here was that the C++ API used char*'s for some things whereas the C API used UChar*'s so we needed to define our own copies of some constants. We also need to manage a buffer ourselves, instead of being able to use the underlying buffer of a retured UnicodeString. --- .../System.Globalization.Native/calendarData.cpp | 42 +++++++++++++++------- src/corefx/System.Globalization.Native/holders.h | 11 ++++++ 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/corefx/System.Globalization.Native/calendarData.cpp b/src/corefx/System.Globalization.Native/calendarData.cpp index 21808f7053..9a9307e855 100644 --- a/src/corefx/System.Globalization.Native/calendarData.cpp +++ b/src/corefx/System.Globalization.Native/calendarData.cpp @@ -26,6 +26,10 @@ #define JAPANESE_LOCALE_AND_CALENDAR "ja_JP@calendar=japanese" +const UChar UDAT_MONTH_DAY_UCHAR[] = {'M', 'M', 'M', 'M', 'd', '\0'}; +const UChar UDAT_YEAR_NUM_MONTH_DAY_UCHAR[] = {'y', 'M', 'd', '\0'}; +const UChar UDAT_YEAR_MONTH_UCHAR[] = {'y', 'M', 'M', 'M', 'M', '\0'}; + /* * These values should be kept in sync with System.Globalization.CalendarId */ @@ -247,15 +251,13 @@ Gets the Month-Day DateTime pattern for the specified locale. CalendarDataResult GetMonthDayPattern(Locale& locale, UChar* sMonthDay, int32_t stringCapacity) { UErrorCode err = U_ZERO_ERROR; - LocalPointer generator(DateTimePatternGenerator::createInstance(locale, err)); - if (U_FAILURE(err)) - return GetCalendarDataResult(err); + UDateTimePatternGenerator* pGenerator = udatpg_open(locale.getName(), &err); + UDateTimePatternGeneratorHolder generatorHolder(pGenerator, err); - UnicodeString monthDayPattern = generator->getBestPattern(UnicodeString(UDAT_MONTH_DAY), err); if (U_FAILURE(err)) return GetCalendarDataResult(err); - monthDayPattern.extract(sMonthDay, stringCapacity, err); + udatpg_getBestPattern(pGenerator, UDAT_MONTH_DAY_UCHAR, -1, sMonthDay, stringCapacity, &err); return GetCalendarDataResult(err); } @@ -342,23 +344,37 @@ Gets the DateTime pattern for the specified skeleton and invokes the callback with the retrieved value. */ bool InvokeCallbackForDateTimePattern(Locale& locale, - const char* patternSkeleton, + const UChar* patternSkeleton, EnumCalendarInfoCallback callback, const void* context) { UErrorCode err = U_ZERO_ERROR; - LocalPointer generator(DateTimePatternGenerator::createInstance(locale, err)); + UDateTimePatternGenerator* pGenerator = udatpg_open(locale.getName(), &err); + UDateTimePatternGeneratorHolder generatorHolder(pGenerator, err); + if (U_FAILURE(err)) return false; - UnicodeString pattern = generator->getBestPattern(UnicodeString(patternSkeleton), err); + UErrorCode ignore = U_ZERO_ERROR; + int32_t patternLen = udatpg_getBestPattern(pGenerator, patternSkeleton, -1, nullptr, 0, &ignore); + + UChar* bestPattern = (UChar*)calloc(patternLen + 1, sizeof(UChar)); + + if (bestPattern == nullptr) + { + return false; + } + + udatpg_getBestPattern(pGenerator, patternSkeleton, -1, bestPattern, patternLen + 1, &err); + if (U_SUCCESS(err)) { - callback(pattern.getTerminatedBuffer(), context); - return true; + callback(bestPattern, context); } - return false; + free(bestPattern); + + return U_SUCCESS(err); } /* @@ -504,7 +520,7 @@ extern "C" int32_t EnumCalendarInfo(EnumCalendarInfoCallback callback, // ShortDates to map kShort and kMedium in ICU, but also adding the "yMd" // skeleton as well, as this // closely matches what is used on Windows - return InvokeCallbackForDateTimePattern(locale, UDAT_YEAR_NUM_MONTH_DAY, callback, context) && + return InvokeCallbackForDateTimePattern(locale, UDAT_YEAR_NUM_MONTH_DAY_UCHAR, callback, context) && InvokeCallbackForDatePattern(locale, DateFormat::kShort, callback, context) && InvokeCallbackForDatePattern(locale, DateFormat::kMedium, callback, context); case LongDates: @@ -512,7 +528,7 @@ extern "C" int32_t EnumCalendarInfo(EnumCalendarInfoCallback callback, return InvokeCallbackForDatePattern(locale, DateFormat::kFull, callback, context) && InvokeCallbackForDatePattern(locale, DateFormat::kLong, callback, context); case YearMonths: - return InvokeCallbackForDateTimePattern(locale, UDAT_YEAR_MONTH, callback, context); + return InvokeCallbackForDateTimePattern(locale, UDAT_YEAR_MONTH_UCHAR, callback, context); case DayNames: return EnumWeekdays( locale, calendarId, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE, callback, context); diff --git a/src/corefx/System.Globalization.Native/holders.h b/src/corefx/System.Globalization.Native/holders.h index ea757fc30d..4c2f7c71d3 100644 --- a/src/corefx/System.Globalization.Native/holders.h +++ b/src/corefx/System.Globalization.Native/holders.h @@ -5,6 +5,7 @@ #include "unicode/ucal.h" #include "unicode/uenum.h" +#include "unicode/udatpg.h" // IcuHolder is a template that can manage the lifetime of a raw pointer to ensure that it is cleaned up at the correct // time. The general usage pattern is to aquire some ICU resource via an _open call, then construct a holder using the @@ -51,5 +52,15 @@ struct UEnumerationCloser } }; +struct UDateTimePatternGeneratorCloser +{ + public: + void operator()(UDateTimePatternGenerator* pGenerator) const + { + udatpg_close(pGenerator); + } +}; + typedef IcuHolder UCalendarHolder; typedef IcuHolder UEnumerationHolder; +typedef IcuHolder UDateTimePatternGeneratorHolder; -- cgit v1.2.3 From 9945e4f995673116a82b73e63520c536ada6934c Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Wed, 14 Oct 2015 17:39:40 -0700 Subject: Convert DateFormat to UDateFormat Remove uses of the C++ DateFormat and SimpleDateFormat classes in favor of UDateFormat. As part of this change, it was easier to move some of the code that converts an ICU format string to a .NET Style format string from native code up to managed code. This code used UnicodeString and we'll need to move away from that as well as we remove all the C++ usage. --- .../System.Globalization.Native/calendarData.cpp | 39 +++++++---- src/corefx/System.Globalization.Native/holders.h | 11 +++ .../localeStringData.cpp | 79 +++------------------- .../System/Globalization/CultureData.Unix.cs | 41 ++++++++++- 4 files changed, 86 insertions(+), 84 deletions(-) diff --git a/src/corefx/System.Globalization.Native/calendarData.cpp b/src/corefx/System.Globalization.Native/calendarData.cpp index 9a9307e855..75336d1f03 100644 --- a/src/corefx/System.Globalization.Native/calendarData.cpp +++ b/src/corefx/System.Globalization.Native/calendarData.cpp @@ -316,24 +316,35 @@ Gets the ICU date pattern for the specified locale and EStyle and invokes the callback with the result. */ bool InvokeCallbackForDatePattern(Locale& locale, - DateFormat::EStyle style, + UDateFormatStyle style, EnumCalendarInfoCallback callback, const void* context) { - LocalPointer dateFormat(DateFormat::createDateInstance(style, locale)); - if (dateFormat.isNull()) + UErrorCode err = U_ZERO_ERROR; + UDateFormat* pFormat = udat_open(UDAT_NONE, style, locale.getName(), nullptr, 0, nullptr, 0, &err); + UDateFormatHolder formatHolder(pFormat, err); + + if (U_FAILURE(err)) return false; - // cast to SimpleDateFormat so we can call toPattern() - SimpleDateFormat* sdf = dynamic_cast(dateFormat.getAlias()); - if (sdf == NULL) + UErrorCode ignore = U_ZERO_ERROR; + int32_t patternLen = udat_toPattern(pFormat, false, nullptr, 0, &ignore); + + UChar* pattern = (UChar*)calloc(patternLen + 1, sizeof(UChar)); + + if (pattern == nullptr) return false; - UnicodeString pattern; - sdf->toPattern(pattern); + udat_toPattern(pFormat, false, pattern, patternLen + 1, &err); - callback(pattern.getTerminatedBuffer(), context); - return true; + if (U_SUCCESS(err)) + { + callback(pattern, context); + } + + free(pattern); + + return U_SUCCESS(err); } /* @@ -521,12 +532,12 @@ extern "C" int32_t EnumCalendarInfo(EnumCalendarInfoCallback callback, // skeleton as well, as this // closely matches what is used on Windows return InvokeCallbackForDateTimePattern(locale, UDAT_YEAR_NUM_MONTH_DAY_UCHAR, callback, context) && - InvokeCallbackForDatePattern(locale, DateFormat::kShort, callback, context) && - InvokeCallbackForDatePattern(locale, DateFormat::kMedium, callback, context); + InvokeCallbackForDatePattern(locale, UDAT_SHORT, callback, context) && + InvokeCallbackForDatePattern(locale, UDAT_MEDIUM, callback, context); case LongDates: // LongDates map to kFull and kLong in ICU. - return InvokeCallbackForDatePattern(locale, DateFormat::kFull, callback, context) && - InvokeCallbackForDatePattern(locale, DateFormat::kLong, callback, context); + return InvokeCallbackForDatePattern(locale, UDAT_FULL, callback, context) && + InvokeCallbackForDatePattern(locale, UDAT_LONG, callback, context); case YearMonths: return InvokeCallbackForDateTimePattern(locale, UDAT_YEAR_MONTH_UCHAR, callback, context); case DayNames: diff --git a/src/corefx/System.Globalization.Native/holders.h b/src/corefx/System.Globalization.Native/holders.h index 4c2f7c71d3..f95e346580 100644 --- a/src/corefx/System.Globalization.Native/holders.h +++ b/src/corefx/System.Globalization.Native/holders.h @@ -6,6 +6,7 @@ #include "unicode/ucal.h" #include "unicode/uenum.h" #include "unicode/udatpg.h" +#include "unicode/udat.h" // IcuHolder is a template that can manage the lifetime of a raw pointer to ensure that it is cleaned up at the correct // time. The general usage pattern is to aquire some ICU resource via an _open call, then construct a holder using the @@ -61,6 +62,16 @@ struct UDateTimePatternGeneratorCloser } }; +struct UDateFormatCloser +{ + public: + void operator()(UDateFormat* pDateFormat) const + { + udat_close(pDateFormat); + } +}; + typedef IcuHolder UCalendarHolder; typedef IcuHolder UEnumerationHolder; typedef IcuHolder UDateTimePatternGeneratorHolder; +typedef IcuHolder UDateFormatHolder; diff --git a/src/corefx/System.Globalization.Native/localeStringData.cpp b/src/corefx/System.Globalization.Native/localeStringData.cpp index bfe04697ea..0dbae258a0 100644 --- a/src/corefx/System.Globalization.Native/localeStringData.cpp +++ b/src/corefx/System.Globalization.Native/localeStringData.cpp @@ -8,16 +8,13 @@ #include #include "locale.hpp" +#include "holders.h" #include "unicode/dcfmtsym.h" //decimal symbols #include "unicode/dtfmtsym.h" //date symbols #include "unicode/smpdtfmt.h" //date format #include "unicode/localpointer.h" -// invariant character definitions used by ICU -#define UCHAR_SPACE ((UChar)0x0020) // space -#define UCHAR_NBSPACE ((UChar)0x00A0) // space - // Enum that corresponds to managed enum CultureData.LocaleStringData. // The numeric values of the enum members match their Win32 counterparts. enum LocaleStringData : int32_t @@ -283,54 +280,11 @@ GetLocaleInfoString(const UChar* localeName, LocaleStringData localeStringData, return UErrorCodeToBool(status); } -/* -Function: -NormalizeTimePattern - -Convert an ICU non-localized time pattern to .NET format -*/ -void NormalizeTimePattern(const UnicodeString* srcPattern, UnicodeString* destPattern) -{ - // An srcPattern example: "h:mm:ss a" - // A destPattern example: "h:mm:ss tt" - destPattern->remove(); - - bool amPmAdded = false; - for (int i = 0; i <= srcPattern->length() - 1; i++) - { - UChar ch = srcPattern->charAt(i); - switch (ch) - { - case ':': - case '.': - case 'H': - case 'h': - case 'm': - case 's': - destPattern->append(ch); - break; - - case UCHAR_SPACE: - case UCHAR_NBSPACE: - destPattern->append(UCHAR_SPACE); - break; - - case 'a': // AM/PM - if (!amPmAdded) - { - amPmAdded = true; - destPattern->append("tt"); - } - break; - } - } -} - /* PAL Function: GetLocaleTimeFormat -Obtains time format information. +Obtains time format information (in ICU format, it needs to be coverted to .NET Format). Returns 1 for success, 0 otherwise */ extern "C" int32_t GetLocaleTimeFormat(const UChar* localeName, int shortFormat, UChar* value, int32_t valueLength) @@ -341,28 +295,15 @@ extern "C" int32_t GetLocaleTimeFormat(const UChar* localeName, int shortFormat, return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); } - DateFormat::EStyle style = (shortFormat != 0) ? DateFormat::kShort : DateFormat::kMedium; - LocalPointer dateFormat(DateFormat::createTimeInstance(style, locale)); - if (dateFormat == NULL || !dateFormat.isValid()) - { - return UErrorCodeToBool(U_MEMORY_ALLOCATION_ERROR); - } - - // cast to SimpleDateFormat so we can call toPattern() - SimpleDateFormat* sdf = dynamic_cast(dateFormat.getAlias()); - if (sdf == NULL) - { - return UErrorCodeToBool(U_INTERNAL_PROGRAM_ERROR); - } - - UnicodeString icuPattern; - sdf->toPattern(icuPattern); + UErrorCode err = U_ZERO_ERROR; + UDateFormatStyle style = (shortFormat != 0) ? UDAT_SHORT : UDAT_MEDIUM; + UDateFormat* pFormat = udat_open(style, UDAT_NONE, locale.getName(), nullptr, 0, nullptr, 0, &err); + UDateFormatHolder formatHolder(pFormat, err); - UnicodeString dotnetPattern; - NormalizeTimePattern(&icuPattern, &dotnetPattern); + if (U_FAILURE(err)) + return UErrorCodeToBool(err); - UErrorCode status = U_ZERO_ERROR; - dotnetPattern.extract(value, valueLength, status); + udat_toPattern(pFormat, false, value, valueLength, &err); - return UErrorCodeToBool(status); + return UErrorCodeToBool(err); } diff --git a/src/mscorlib/corefx/System/Globalization/CultureData.Unix.cs b/src/mscorlib/corefx/System/Globalization/CultureData.Unix.cs index f53d7ceb77..300adc90c4 100644 --- a/src/mscorlib/corefx/System/Globalization/CultureData.Unix.cs +++ b/src/mscorlib/corefx/System/Globalization/CultureData.Unix.cs @@ -213,7 +213,8 @@ namespace System.Globalization Contract.Assert(false, "[CultureData.GetTimeFormatString(bool shortFormat)] Failed"); return String.Empty; } - return StringBuilderCache.GetStringAndRelease(sb); + + return ConvertIcuTimeFormatString(StringBuilderCache.GetStringAndRelease(sb)); } private int GetFirstDayOfWeek() @@ -254,5 +255,43 @@ namespace System.Globalization { return CultureInfo.GetUserDefaultCulture(); } + + private static string ConvertIcuTimeFormatString(string icuFormatString) + { + StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_FULLNAME_CAPACITY); + bool amPmAdded = false; + + for (int i = 0; i < icuFormatString.Length; i++) + { + switch(icuFormatString[i]) + { + case ':': + case '.': + case 'H': + case 'h': + case 'm': + case 's': + sb.Append(icuFormatString[i]); + break; + + case ' ': + case '\u00A0': + // Convert nonbreaking spaces into regular spaces + sb.Append(' '); + break; + + case 'a': // AM/PM + if (!amPmAdded) + { + amPmAdded = true; + sb.Append("tt"); + } + break; + + } + } + + return StringBuilderCache.GetStringAndRelease(sb); + } } } -- cgit v1.2.3 From 39edeba2aeb24623425a72f95aa748e51e6242fe Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Thu, 15 Oct 2015 11:20:59 -0700 Subject: Remove use of ICU C++ DateFormatSymbols --- .../System.Globalization.Native/localeStringData.cpp | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/corefx/System.Globalization.Native/localeStringData.cpp b/src/corefx/System.Globalization.Native/localeStringData.cpp index 0dbae258a0..a87ba06622 100644 --- a/src/corefx/System.Globalization.Native/localeStringData.cpp +++ b/src/corefx/System.Globalization.Native/localeStringData.cpp @@ -102,31 +102,21 @@ UErrorCode GetDigitSymbol(const Locale& locale, Function: GetLocaleInfoAmPm -Obtains the value of a DateFormatSymbols Am or Pm string +Obtains the value of the AM or PM string for a locale. */ UErrorCode GetLocaleInfoAmPm(const Locale& locale, bool am, UChar* value, int32_t valueLength) { UErrorCode status = U_ZERO_ERROR; - LocalPointer dateFormatSymbols(new DateFormatSymbols(locale, status)); - if (dateFormatSymbols == NULL) - { - status = U_MEMORY_ALLOCATION_ERROR; - } + UDateFormat* pFormat = udat_open(UDAT_DEFAULT, UDAT_DEFAULT, locale.getName(), nullptr, 0, nullptr, 0, &status); + UDateFormatHolder formatHolder(pFormat, status); if (U_FAILURE(status)) { return status; } - int32_t count = 0; - const UnicodeString* tempStr = dateFormatSymbols->getAmPmStrings(count); - int offset = am ? 0 : 1; - if (offset >= count) - { - return U_INTERNAL_PROGRAM_ERROR; - } + udat_getSymbols(pFormat, UDAT_AM_PMS, am ? 0 : 1, value, valueLength, &status); - tempStr[offset].extract(value, valueLength, status); return status; } -- cgit v1.2.3 From 3029f7638c10db46f28981d94c06097efce7d6f6 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Thu, 15 Oct 2015 14:59:26 -0700 Subject: Remove use of ICU C++ NumberFormat class This change removes NumberFormat in favor of UNumberFormat. There is a bit of work that needs to happen in order to keep the normalization code we use to convert an ICU pattern so to something we can match against working. Instead of UnicodeStrings, the input to the normalization function is now a UChar* and we build up a std::string during normalization. This allows us to also skip a conversion from UChar* back to char* so we can find the correct pattern in our collection of patterns to examine. --- src/corefx/System.Globalization.Native/holders.h | 10 ++ .../localeNumberData.cpp | 137 +++++++++++---------- 2 files changed, 82 insertions(+), 65 deletions(-) diff --git a/src/corefx/System.Globalization.Native/holders.h b/src/corefx/System.Globalization.Native/holders.h index f95e346580..2606e48969 100644 --- a/src/corefx/System.Globalization.Native/holders.h +++ b/src/corefx/System.Globalization.Native/holders.h @@ -7,6 +7,7 @@ #include "unicode/uenum.h" #include "unicode/udatpg.h" #include "unicode/udat.h" +#include "unicode/unum.h" // IcuHolder is a template that can manage the lifetime of a raw pointer to ensure that it is cleaned up at the correct // time. The general usage pattern is to aquire some ICU resource via an _open call, then construct a holder using the @@ -71,7 +72,16 @@ struct UDateFormatCloser } }; +struct UNumberFormatCloser +{ + void operator()(UNumberFormat* pNumberFormat) const + { + udat_close(pNumberFormat); + } +}; + typedef IcuHolder UCalendarHolder; typedef IcuHolder UEnumerationHolder; typedef IcuHolder UDateTimePatternGeneratorHolder; typedef IcuHolder UDateFormatHolder; +typedef IcuHolder UNumberFormatHolder; diff --git a/src/corefx/System.Globalization.Native/localeNumberData.cpp b/src/corefx/System.Globalization.Native/localeNumberData.cpp index a73bdc1188..79dcd78cb3 100644 --- a/src/corefx/System.Globalization.Native/localeNumberData.cpp +++ b/src/corefx/System.Globalization.Native/localeNumberData.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "locale.hpp" #include "holders.h" @@ -64,7 +65,7 @@ NormalizeNumericPattern Returns a numeric string pattern in a format that we can match against the appropriate managed pattern. */ -void NormalizeNumericPattern(const UnicodeString* srcPattern, UnicodeString* destPattern, bool isNegative) +std::string NormalizeNumericPattern(const UChar* srcPattern, bool isNegative) { // A srcPattern example: "#,##0.00 C;(#,##0.00 C)" but where C is the // international currency symbol (UCHAR_CURRENCY) @@ -72,11 +73,20 @@ void NormalizeNumericPattern(const UnicodeString* srcPattern, UnicodeString* des // separated by a semicolon // A destPattern example: "(C n)" where C represents the currency symbol, and // n is the number - destPattern->remove(); + std::string destPattern; int iStart = 0; - int iEnd = srcPattern->length() - 1; - int32_t iNegativePatternStart = srcPattern->indexOf(UCHAR_SEMICOLON); + int iEnd = u_strlen(srcPattern); + int32_t iNegativePatternStart = -1; + + for (int i = iStart; i < iEnd; i++) + { + if (srcPattern[i] == ';') + { + iNegativePatternStart = i; + } + } + if (iNegativePatternStart >= 0) { if (isNegative) @@ -96,14 +106,14 @@ void NormalizeNumericPattern(const UnicodeString* srcPattern, UnicodeString* des for (int i = iStart; i <= iEnd; i++) { - UChar ch = srcPattern->charAt(i); + UChar ch = srcPattern[i]; switch (ch) { case UCHAR_DIGIT: if (!digitAdded) { digitAdded = true; - destPattern->append('n'); + destPattern.push_back('n'); } break; @@ -111,7 +121,7 @@ void NormalizeNumericPattern(const UnicodeString* srcPattern, UnicodeString* des if (!currencyAdded) { currencyAdded = true; - destPattern->append('C'); + destPattern.push_back('C'); } break; @@ -120,7 +130,7 @@ void NormalizeNumericPattern(const UnicodeString* srcPattern, UnicodeString* des if (!spaceAdded) { spaceAdded = true; - destPattern->append(UCHAR_SPACE); + destPattern.push_back(' '); } else { @@ -132,11 +142,11 @@ void NormalizeNumericPattern(const UnicodeString* srcPattern, UnicodeString* des case UCHAR_OPENPAREN: case UCHAR_CLOSEPAREN: minusAdded = true; - destPattern->append(ch); + destPattern.push_back(static_cast(ch)); break; case UCHAR_PERCENT: - destPattern->append(ch); + destPattern.push_back('%'); break; } } @@ -145,8 +155,10 @@ void NormalizeNumericPattern(const UnicodeString* srcPattern, UnicodeString* des // minus sign if (isNegative && !minusAdded) { - destPattern->insert(0, UCHAR_MINUS); + destPattern.insert(destPattern.begin(), '-'); } + + return destPattern; } /* @@ -157,30 +169,35 @@ Determines the pattern from the decimalFormat and returns the matching pattern's index from patterns[]. Returns index -1 if no pattern is found. */ -int GetNumericPattern(DecimalFormat* decimalFormat, const char* patterns[], int patternsCount, bool isNegative) +int GetNumericPattern(const UNumberFormat* pNumberFormat, const char* patterns[], int patternsCount, bool isNegative) { const int INVALID_FORMAT = -1; const int MAX_DOTNET_NUMERIC_PATTERN_LENGTH = 6; // example: "(C n)" plus terminator - char charPattern[MAX_DOTNET_NUMERIC_PATTERN_LENGTH] = {0}; - UnicodeString icuPattern; - decimalFormat->toPattern(icuPattern); + UErrorCode ignore = U_ZERO_ERROR; + int32_t icuPatternLength = unum_toPattern(pNumberFormat, false, nullptr, 0, &ignore); + + std::vector icuPattern(icuPatternLength + 1, '\0'); + + UErrorCode err = U_ZERO_ERROR; - UnicodeString normalizedPattern; - NormalizeNumericPattern(&icuPattern, &normalizedPattern, isNegative); + unum_toPattern(pNumberFormat, false, icuPattern.data(), icuPattern.size(), &err); + + assert(U_SUCCESS(err)); + + std::string normalizedPattern = NormalizeNumericPattern(icuPattern.data(), isNegative); assert(normalizedPattern.length() > 0); assert(normalizedPattern.length() < MAX_DOTNET_NUMERIC_PATTERN_LENGTH); + if (normalizedPattern.length() == 0 || normalizedPattern.length() >= MAX_DOTNET_NUMERIC_PATTERN_LENGTH) { return INVALID_FORMAT; } - u_UCharsToChars(normalizedPattern.getTerminatedBuffer(), charPattern, normalizedPattern.length() + 1); - for (int i = 0; i < patternsCount; i++) { - if (strcmp(charPattern, patterns[i]) == 0) + if (strcmp(normalizedPattern.c_str(), patterns[i]) == 0) { return i; } @@ -218,19 +235,17 @@ int GetCurrencyNegativePattern(const Locale& locale) "(n C)"}; UErrorCode status = U_ZERO_ERROR; - LocalPointer format(NumberFormat::createInstance(locale, UNUM_CURRENCY, status)); + UNumberFormat* pFormat = unum_open(UNUM_CURRENCY, nullptr, 0, locale.getName(), nullptr, &status); + UNumberFormatHolder formatHolder(pFormat, status); + assert(U_SUCCESS(status)); + if (U_SUCCESS(status)) { - DecimalFormat* decimalFormat = dynamic_cast(format.getAlias()); - assert(decimalFormat != NULL); - if (decimalFormat != NULL) + int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), true); + if (value >= 0) { - int value = GetNumericPattern(decimalFormat, Patterns, ARRAY_LENGTH(Patterns), true); - if (value >= 0) - { - return value; - } + return value; } } @@ -250,19 +265,17 @@ int GetCurrencyPositivePattern(const Locale& locale) static const char* Patterns[] = {"Cn", "nC", "C n", "n C"}; UErrorCode status = U_ZERO_ERROR; - LocalPointer format(NumberFormat::createInstance(locale, UNUM_CURRENCY, status)); + UNumberFormat* pFormat = unum_open(UNUM_CURRENCY, nullptr, 0, locale.getName(), nullptr, &status); + UNumberFormatHolder formatHolder(pFormat, status); + assert(U_SUCCESS(status)); + if (U_SUCCESS(status)) { - DecimalFormat* decimalFormat = dynamic_cast(format.getAlias()); - assert(decimalFormat != NULL); - if (decimalFormat != NULL) + int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), false); + if (value >= 0) { - int value = GetNumericPattern(decimalFormat, Patterns, ARRAY_LENGTH(Patterns), false); - if (value >= 0) - { - return value; - } + return value; } } @@ -282,19 +295,17 @@ int GetNumberNegativePattern(const Locale& locale) static const char* Patterns[] = {"(n)", "-n", "- n", "n-", "n -"}; UErrorCode status = U_ZERO_ERROR; - LocalPointer format(NumberFormat::createInstance(locale, UNUM_DECIMAL, status)); + UNumberFormat* pFormat = unum_open(UNUM_DECIMAL, nullptr, 0, locale.getName(), nullptr, &status); + UNumberFormatHolder formatHolder(pFormat, status); + assert(U_SUCCESS(status)); + if (U_SUCCESS(status)) { - DecimalFormat* decimalFormat = dynamic_cast(format.getAlias()); - assert(decimalFormat != NULL); - if (decimalFormat != NULL) + int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), true); + if (value >= 0) { - int value = GetNumericPattern(decimalFormat, Patterns, ARRAY_LENGTH(Patterns), true); - if (value >= 0) - { - return value; - } + return value; } } @@ -315,19 +326,17 @@ int GetPercentNegativePattern(const Locale& locale) "-n %", "-n%", "-%n", "%-n", "%n-", "n-%", "n%-", "-% n", "n %-", "% n-", "% -n", "n- %"}; UErrorCode status = U_ZERO_ERROR; - LocalPointer format(NumberFormat::createInstance(locale, UNUM_PERCENT, status)); + UNumberFormat* pFormat = unum_open(UNUM_PERCENT, nullptr, 0, locale.getName(), nullptr, &status); + UNumberFormatHolder formatHolder(pFormat, status); + assert(U_SUCCESS(status)); + if (U_SUCCESS(status)) { - DecimalFormat* decimalFormat = dynamic_cast(format.getAlias()); - assert(decimalFormat != NULL); - if (decimalFormat != NULL) + int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), true); + if (value >= 0) { - int value = GetNumericPattern(decimalFormat, Patterns, ARRAY_LENGTH(Patterns), true); - if (value >= 0) - { - return value; - } + return value; } } @@ -347,19 +356,17 @@ int GetPercentPositivePattern(const Locale& locale) static const char* Patterns[] = {"n %", "n%", "%n", "% n"}; UErrorCode status = U_ZERO_ERROR; - LocalPointer format(NumberFormat::createInstance(locale, UNUM_PERCENT, status)); + UNumberFormat* pFormat = unum_open(UNUM_PERCENT, nullptr, 0, locale.getName(), nullptr, &status); + UNumberFormatHolder formatHolder(pFormat, status); + assert(U_SUCCESS(status)); + if (U_SUCCESS(status)) { - DecimalFormat* decimalFormat = dynamic_cast(format.getAlias()); - assert(decimalFormat != NULL); - if (decimalFormat != NULL) + int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), false); + if (value >= 0) { - int value = GetNumericPattern(decimalFormat, Patterns, ARRAY_LENGTH(Patterns), false); - if (value >= 0) - { - return value; - } + return value; } } -- cgit v1.2.3 From dc4b128c177329cf26da244f99730da5732ec211 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Thu, 15 Oct 2015 16:00:35 -0700 Subject: Remove ICU C++ LocaleDisplayNames --- src/corefx/System.Globalization.Native/calendarData.cpp | 10 ++++------ src/corefx/System.Globalization.Native/holders.h | 10 ++++++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/corefx/System.Globalization.Native/calendarData.cpp b/src/corefx/System.Globalization.Native/calendarData.cpp index 75336d1f03..27f51bfeb2 100644 --- a/src/corefx/System.Globalization.Native/calendarData.cpp +++ b/src/corefx/System.Globalization.Native/calendarData.cpp @@ -271,13 +271,11 @@ Gets the native calendar name. CalendarDataResult GetNativeCalendarName(Locale& locale, CalendarId calendarId, UChar* nativeName, int32_t stringCapacity) { - LocalPointer displayNames(LocaleDisplayNames::createInstance(locale)); - - UnicodeString calendarName; - displayNames->keyValueDisplayName("calendar", GetCalendarName(calendarId), calendarName); - UErrorCode err = U_ZERO_ERROR; - calendarName.extract(nativeName, stringCapacity, err); + ULocaleDisplayNames* pDisplayNames = uldn_open(locale.getName(), ULDN_STANDARD_NAMES, &err); + ULocaleDisplayNamesHolder displayNamesHolder(pDisplayNames, err); + + uldn_keyValueDisplayName(pDisplayNames, "calendar", GetCalendarName(calendarId), nativeName, stringCapacity, &err); return GetCalendarDataResult(err); } diff --git a/src/corefx/System.Globalization.Native/holders.h b/src/corefx/System.Globalization.Native/holders.h index 2606e48969..0658e551c1 100644 --- a/src/corefx/System.Globalization.Native/holders.h +++ b/src/corefx/System.Globalization.Native/holders.h @@ -8,6 +8,7 @@ #include "unicode/udatpg.h" #include "unicode/udat.h" #include "unicode/unum.h" +#include "unicode/uldnames.h" // IcuHolder is a template that can manage the lifetime of a raw pointer to ensure that it is cleaned up at the correct // time. The general usage pattern is to aquire some ICU resource via an _open call, then construct a holder using the @@ -80,8 +81,17 @@ struct UNumberFormatCloser } }; +struct ULocaleDisplayNamesCloser +{ + void operator()(ULocaleDisplayNames* pLocaleDisplayNames) const + { + uldn_close(pLocaleDisplayNames); + } +}; + typedef IcuHolder UCalendarHolder; typedef IcuHolder UEnumerationHolder; typedef IcuHolder UDateTimePatternGeneratorHolder; typedef IcuHolder UDateFormatHolder; typedef IcuHolder UNumberFormatHolder; +typedef IcuHolder ULocaleDisplayNamesHolder; -- cgit v1.2.3 From 47b624f56d1e961e544fd0e5aecb0c873404b9b9 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Thu, 15 Oct 2015 16:35:28 -0700 Subject: Remove useage of ICU C++ DecimalFormatSymbols --- .../localeStringData.cpp | 64 ++++++++-------------- 1 file changed, 24 insertions(+), 40 deletions(-) diff --git a/src/corefx/System.Globalization.Native/localeStringData.cpp b/src/corefx/System.Globalization.Native/localeStringData.cpp index a87ba06622..b0a5cf9a00 100644 --- a/src/corefx/System.Globalization.Native/localeStringData.cpp +++ b/src/corefx/System.Globalization.Native/localeStringData.cpp @@ -54,26 +54,20 @@ GetLocaleInfoDecimalFormatSymbol Obtains the value of a DecimalFormatSymbols */ -UErrorCode GetLocaleInfoDecimalFormatSymbol(const Locale& locale, - DecimalFormatSymbols::ENumberFormatSymbol symbol, - UChar* value, - int32_t valueLength) +UErrorCode +GetLocaleInfoDecimalFormatSymbol(const Locale& locale, UNumberFormatSymbol symbol, UChar* value, int32_t valueLength) { UErrorCode status = U_ZERO_ERROR; - LocalPointer decimalsymbols(new DecimalFormatSymbols(locale, status)); - if (decimalsymbols == NULL) - { - status = U_MEMORY_ALLOCATION_ERROR; - } + UNumberFormat* pFormat = unum_open(UNUM_DECIMAL, nullptr, 0, locale.getName(), nullptr, &status); + UNumberFormatHolder formatHolder(pFormat, status); if (U_FAILURE(status)) { return status; } - UnicodeString s = decimalsymbols->getSymbol(symbol); + unum_getSymbol(pFormat, symbol, value, valueLength, &status); - s.extract(value, valueLength, status); return status; } @@ -85,7 +79,7 @@ Obtains the value of a Digit DecimalFormatSymbols */ UErrorCode GetDigitSymbol(const Locale& locale, UErrorCode previousStatus, - DecimalFormatSymbols::ENumberFormatSymbol symbol, + UNumberFormatSymbol symbol, int digit, UChar* value, int32_t valueLength) @@ -175,40 +169,33 @@ GetLocaleInfoString(const UChar* localeName, LocaleStringData localeStringData, case ListSeparator: // fall through case ThousandSeparator: - status = GetLocaleInfoDecimalFormatSymbol( - locale, DecimalFormatSymbols::kGroupingSeparatorSymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_GROUPING_SEPARATOR_SYMBOL, value, valueLength); break; case DecimalSeparator: - status = GetLocaleInfoDecimalFormatSymbol( - locale, DecimalFormatSymbols::kDecimalSeparatorSymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_DECIMAL_SEPARATOR_SYMBOL, value, valueLength); break; case Digits: - status = GetDigitSymbol(locale, status, DecimalFormatSymbols::kZeroDigitSymbol, 0, value, valueLength); - // symbols kOneDigitSymbol to kNineDigitSymbol are contiguous - for (int32_t symbol = DecimalFormatSymbols::kOneDigitSymbol; - symbol <= DecimalFormatSymbols::kNineDigitSymbol; - symbol++) + status = GetDigitSymbol(locale, status, UNUM_ZERO_DIGIT_SYMBOL, 0, value, valueLength); + // symbols UNUM_ONE_DIGIT to UNUM_NINE_DIGIT are contiguous + for (int32_t symbol = UNUM_ONE_DIGIT_SYMBOL; symbol <= UNUM_NINE_DIGIT_SYMBOL; symbol++) { - int charIndex = symbol - DecimalFormatSymbols::kOneDigitSymbol + 1; + int charIndex = symbol - UNUM_ONE_DIGIT_SYMBOL + 1; status = GetDigitSymbol( - locale, status, (DecimalFormatSymbols::ENumberFormatSymbol)symbol, charIndex, value, valueLength); + locale, status, static_cast(symbol), charIndex, value, valueLength); } break; case MonetarySymbol: - status = - GetLocaleInfoDecimalFormatSymbol(locale, DecimalFormatSymbols::kCurrencySymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_CURRENCY_SYMBOL, value, valueLength); break; case Iso4217MonetarySymbol: - status = - GetLocaleInfoDecimalFormatSymbol(locale, DecimalFormatSymbols::kIntlCurrencySymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_INTL_CURRENCY_SYMBOL, value, valueLength); break; case MonetaryDecimalSeparator: - status = GetLocaleInfoDecimalFormatSymbol( - locale, DecimalFormatSymbols::kMonetarySeparatorSymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MONETARY_SEPARATOR_SYMBOL, value, valueLength); break; case MonetaryThousandSeparator: - status = GetLocaleInfoDecimalFormatSymbol( - locale, DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol, value, valueLength); + status = + GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL, value, valueLength); break; case AMDesignator: status = GetLocaleInfoAmPm(locale, true, value, valueLength); @@ -217,12 +204,10 @@ GetLocaleInfoString(const UChar* localeName, LocaleStringData localeStringData, status = GetLocaleInfoAmPm(locale, false, value, valueLength); break; case PositiveSign: - status = - GetLocaleInfoDecimalFormatSymbol(locale, DecimalFormatSymbols::kPlusSignSymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PLUS_SIGN_SYMBOL, value, valueLength); break; case NegativeSign: - status = - GetLocaleInfoDecimalFormatSymbol(locale, DecimalFormatSymbols::kMinusSignSymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MINUS_SIGN_SYMBOL, value, valueLength); break; case Iso639LanguageName: status = u_charsToUChars_safe(locale.getLanguage(), value, valueLength); @@ -233,11 +218,10 @@ GetLocaleInfoString(const UChar* localeName, LocaleStringData localeStringData, status = u_charsToUChars_safe(locale.getCountry(), value, valueLength); break; case NaNSymbol: - status = GetLocaleInfoDecimalFormatSymbol(locale, DecimalFormatSymbols::kNaNSymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_NAN_SYMBOL, value, valueLength); break; case PositiveInfinitySymbol: - status = - GetLocaleInfoDecimalFormatSymbol(locale, DecimalFormatSymbols::kInfinitySymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_INFINITY_SYMBOL, value, valueLength); break; case ParentName: { @@ -257,10 +241,10 @@ GetLocaleInfoString(const UChar* localeName, LocaleStringData localeStringData, break; } case PercentSymbol: - status = GetLocaleInfoDecimalFormatSymbol(locale, DecimalFormatSymbols::kPercentSymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PERCENT_SYMBOL, value, valueLength); break; case PerMilleSymbol: - status = GetLocaleInfoDecimalFormatSymbol(locale, DecimalFormatSymbols::kPerMillSymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PERMILL_SYMBOL, value, valueLength); break; default: status = U_UNSUPPORTED_ERROR; -- cgit v1.2.3 From d77e6b48cc57c369e5126856ba892b1e10a7bc62 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Mon, 19 Oct 2015 13:40:58 -0700 Subject: Remove use of ICU C++ DateFormatSymbols --- .../System.Globalization.Native/calendarData.cpp | 107 ++++++++++----------- 1 file changed, 49 insertions(+), 58 deletions(-) diff --git a/src/corefx/System.Globalization.Native/calendarData.cpp b/src/corefx/System.Globalization.Native/calendarData.cpp index 27f51bfeb2..22fccc8297 100644 --- a/src/corefx/System.Globalization.Native/calendarData.cpp +++ b/src/corefx/System.Globalization.Native/calendarData.cpp @@ -5,6 +5,7 @@ #include #include +#include #include "locale.hpp" #include "holders.h" @@ -408,59 +409,59 @@ bool EnumCalendarArray(const UnicodeString* srcArray, /* Function: -EnumWeekdays +EnumSymbols -Enumerates all the weekday names of the specified context and width, invoking -the callback function -for each weekday name. +Enumerates of of the symbols of a type for a locale and calendar and invokes a callback +for each value. */ -bool EnumWeekdays(Locale& locale, - CalendarId calendarId, - DateFormatSymbols::DtContextType dtContext, - DateFormatSymbols::DtWidthType dtWidth, - EnumCalendarInfoCallback callback, - const void* context) +bool EnumSymbols(Locale& locale, + CalendarId calendarId, + UDateFormatSymbolType type, + int32_t startIndex, + EnumCalendarInfoCallback callback, + const void* context) { UErrorCode err = U_ZERO_ERROR; - DateFormatSymbols dateFormatSymbols(locale, GetCalendarName(calendarId), err); + UDateFormat* pFormat = udat_open(UDAT_DEFAULT, UDAT_DEFAULT, locale.getName(), nullptr, 0, nullptr, 0, &err); + UDateFormatHolder formatHolder(pFormat, err); + if (U_FAILURE(err)) return false; - int32_t daysCount; - const UnicodeString* dayNames = dateFormatSymbols.getWeekdays(daysCount, dtContext, dtWidth); - - // ICU returns an empty string for the first/zeroth element in the weekdays - // array. - // So skip the first element. - dayNames++; - daysCount--; + Locale localeWithCalendar(locale); + localeWithCalendar.setKeywordValue("calendar", GetCalendarName(calendarId), err); - return EnumCalendarArray(dayNames, daysCount, callback, context); -} + if (U_FAILURE(err)) + return false; -/* -Function: -EnumMonths + UCalendar* pCalendar = ucal_open(nullptr, 0, localeWithCalendar.getName(), UCAL_DEFAULT, &err); + UCalendarHolder calenderHolder(pCalendar, err); -Enumerates all the month names of the specified context and width, invoking the -callback function -for each month name. -*/ -bool EnumMonths(Locale& locale, - CalendarId calendarId, - DateFormatSymbols::DtContextType dtContext, - DateFormatSymbols::DtWidthType dtWidth, - EnumCalendarInfoCallback callback, - const void* context) -{ - UErrorCode err = U_ZERO_ERROR; - DateFormatSymbols dateFormatSymbols(locale, GetCalendarName(calendarId), err); if (U_FAILURE(err)) return false; - int32_t monthsCount; - const UnicodeString* monthNames = dateFormatSymbols.getMonths(monthsCount, dtContext, dtWidth); - return EnumCalendarArray(monthNames, monthsCount, callback, context); + udat_setCalendar(pFormat, pCalendar); + + int32_t symbolCount = udat_countSymbols(pFormat, type); + + for (int32_t i = startIndex; i < symbolCount; i++) + { + UErrorCode ignore = U_ZERO_ERROR; + int symbolLen = udat_getSymbols(pFormat, type, i, nullptr, 0, &ignore); + + std::vector symbolBuf(symbolLen + 1, '\0'); + + udat_getSymbols(pFormat, type, i, symbolBuf.data(), symbolBuf.size(), &err); + + assert(U_SUCCESS(err)); + + if (U_FAILURE(err)) + return false; + + callback(symbolBuf.data(), context); + } + + return true; } /* @@ -539,33 +540,23 @@ extern "C" int32_t EnumCalendarInfo(EnumCalendarInfoCallback callback, case YearMonths: return InvokeCallbackForDateTimePattern(locale, UDAT_YEAR_MONTH_UCHAR, callback, context); case DayNames: - return EnumWeekdays( - locale, calendarId, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE, callback, context); + return EnumSymbols(locale, calendarId, UDAT_STANDALONE_WEEKDAYS, 1, callback, context); case AbbrevDayNames: - return EnumWeekdays( - locale, calendarId, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED, callback, context); + return EnumSymbols(locale, calendarId, UDAT_STANDALONE_SHORT_WEEKDAYS, 1, callback, context); case MonthNames: - return EnumMonths( - locale, calendarId, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE, callback, context); + return EnumSymbols(locale, calendarId, UDAT_STANDALONE_MONTHS, 0, callback, context); case AbbrevMonthNames: - return EnumMonths( - locale, calendarId, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED, callback, context); + return EnumSymbols(locale, calendarId, UDAT_STANDALONE_SHORT_MONTHS, 0, callback, context); case SuperShortDayNames: #ifdef HAVE_DTWIDTHTYPE_SHORT - return EnumWeekdays( - locale, calendarId, DateFormatSymbols::STANDALONE, DateFormatSymbols::SHORT, callback, context); + return EnumSymbols(locale, calendarId, UDAT_STANDALONE_SHORTER_WEEKDAYS, 1, callback, context); #else - // Currently CentOS-7 uses ICU-50 and ::SHORT was added in ICU-51, so use - // ::NARROW instead - return EnumWeekdays( - locale, calendarId, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW, callback, context); + return EnumSymbols(locale, calendarId, UDAT_STANDALONE_NARROW_WEEKDAYS, 1, callback, context); #endif case MonthGenitiveNames: - return EnumMonths( - locale, calendarId, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE, callback, context); + return EnumSymbols(locale, calendarId, UDAT_MONTHS, 0, callback, context); case AbbrevMonthGenitiveNames: - return EnumMonths( - locale, calendarId, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED, callback, context); + return EnumSymbols(locale, calendarId, UDAT_SHORT_MONTHS, 0, callback, context); case EraNames: case AbbrevEraNames: return EnumEraNames(locale, calendarId, dataType, callback, context); -- cgit v1.2.3 From 3ffad1c903729f6dc5a0b44422a2d8abdeaf9aac Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Tue, 20 Oct 2015 14:29:59 -0700 Subject: Get Eras using ICU C API instead of C++ Getting the regular eras is straight forward, we can do the thing we do for other locale data and just ask ICU using a specific UDateFormatSymbolType. For abbreviated eras, there's no C API, but we can try to just read the data from ICU resources and fall back to the standard width eras if that doesn't work. --- .../System.Globalization.Native/calendarData.cpp | 132 +++++++++++++-------- src/corefx/System.Globalization.Native/holders.h | 10 ++ 2 files changed, 93 insertions(+), 49 deletions(-) diff --git a/src/corefx/System.Globalization.Native/calendarData.cpp b/src/corefx/System.Globalization.Native/calendarData.cpp index 22fccc8297..c0940ecf14 100644 --- a/src/corefx/System.Globalization.Native/calendarData.cpp +++ b/src/corefx/System.Globalization.Native/calendarData.cpp @@ -387,26 +387,6 @@ bool InvokeCallbackForDateTimePattern(Locale& locale, return U_SUCCESS(err); } -/* -Function: -EnumCalendarArray - -Enumerates an array of strings and invokes the callback for each value. -*/ -bool EnumCalendarArray(const UnicodeString* srcArray, - int32_t srcArrayCount, - EnumCalendarInfoCallback callback, - const void* context) -{ - for (int i = 0; i < srcArrayCount; i++) - { - UnicodeString src = srcArray[i]; - callback(src.getTerminatedBuffer(), context); - } - - return true; -} - /* Function: EnumSymbols @@ -464,44 +444,97 @@ bool EnumSymbols(Locale& locale, return true; } +bool EnumUResourceBundle(const UResourceBundle* bundle, EnumCalendarInfoCallback callback, const void* context) +{ + int32_t eraNameCount = ures_getSize(bundle); + + for (int i = 0; i < eraNameCount; i++) + { + UErrorCode status = U_ZERO_ERROR; + int32_t ignore; // We don't care about the length of the string as it is null terminated. + const UChar* eraName = ures_getStringByIndex(bundle, i, &ignore, &status); + + if (U_SUCCESS(status)) + { + callback(eraName, context); + } + } + + return true; +} + /* Function: -EnumEraNames +EnumAbbrevEraNames -Enumerates all the era names of the specified locale and calendar, invoking the -callback function -for each era name. +Enumerates all the abbreviated era names of the specified locale and calendar, invoking the +callback function for each era name. */ -bool EnumEraNames(Locale& locale, - CalendarId calendarId, - CalendarDataType dataType, - EnumCalendarInfoCallback callback, - const void* context) +bool EnumAbbrevEraNames(Locale& locale, CalendarId calendarId, EnumCalendarInfoCallback callback, const void* context) { - UErrorCode err = U_ZERO_ERROR; - const char* calendarName = GetCalendarName(calendarId); - DateFormatSymbols dateFormatSymbols(locale, calendarName, err); - if (U_FAILURE(err)) - return false; + // The C-API for ICU provides no way to get at the abbreviated era names for a calendar (so we can't use EnumSymbols + // here). Instead we will try to walk the ICU resource tables directly and fall back to regular era names if can't + // find good data. + char localeNameBuf[ULOC_FULLNAME_CAPACITY]; + char parentNameBuf[ULOC_FULLNAME_CAPACITY]; - int32_t eraNameCount; - const UnicodeString* eraNames; + char* localeNamePtr = localeNameBuf; + char* parentNamePtr = parentNameBuf; - if (dataType == EraNames) - { - eraNames = dateFormatSymbols.getEras(eraNameCount); - } - else if (dataType == AbbrevEraNames) - { - eraNames = dateFormatSymbols.getNarrowEras(eraNameCount); - } - else + strncpy(localeNamePtr, locale.getName(), ULOC_FULLNAME_CAPACITY); + + while (true) { - assert(false); - return false; + UErrorCode status = U_ZERO_ERROR; + + UResourceBundle* rootResBundle = ures_open(nullptr, localeNamePtr, &status); + UResourceBundleHolder rootResBundleHolder(rootResBundle, status); + + UResourceBundle* calResBundle = ures_getByKey(rootResBundle, "calendar", nullptr, &status); + UResourceBundleHolder calResBundleHolder(calResBundle, status); + + UResourceBundle* targetCalResBundle = + ures_getByKey(calResBundle, GetCalendarName(calendarId), nullptr, &status); + UResourceBundleHolder targetCalResBundleHolder(targetCalResBundle, status); + + UResourceBundle* erasColResBundle = ures_getByKey(targetCalResBundle, "eras", nullptr, &status); + UResourceBundleHolder erasColResBundleHolder(erasColResBundle, status); + + UResourceBundle* erasResBundle = ures_getByKey(erasColResBundle, "narrow", nullptr, &status); + UResourceBundleHolder erasResBundleHolder(erasResBundle, status); + + if (U_SUCCESS(status)) + { + EnumUResourceBundle(erasResBundle, callback, context); + return true; + } + + // Couldn't find the data we need for this locale, we should fallback. + if (localeNameBuf[0] == 0x0) + { + // We are already at the root locale so there is nothing to fall back to, just use the regular eras. + break; + } + + uloc_getParent(localeNamePtr, parentNamePtr, ULOC_FULLNAME_CAPACITY, &status); + + if (U_FAILURE(status)) + { + // Something bad happened getting the parent name, bail out. + break; + } + + // Swap localeNamePtr and parentNamePtr, parentNamePtr is what we want to use on the next iteration + // and we can use the current localeName as scratch space if we have to fall back on that + // iteration. + + char* temp = localeNamePtr; + localeNamePtr = parentNamePtr; + parentNamePtr = temp; } - return EnumCalendarArray(eraNames, eraNameCount, callback, context); + // Walking the resource bundles didn't work, just use the regular eras. + return EnumSymbols(locale, calendarId, UDAT_ERAS, 0, callback, context); } /* @@ -558,8 +591,9 @@ extern "C" int32_t EnumCalendarInfo(EnumCalendarInfoCallback callback, case AbbrevMonthGenitiveNames: return EnumSymbols(locale, calendarId, UDAT_SHORT_MONTHS, 0, callback, context); case EraNames: + return EnumSymbols(locale, calendarId, UDAT_ERAS, 0, callback, context); case AbbrevEraNames: - return EnumEraNames(locale, calendarId, dataType, callback, context); + return EnumAbbrevEraNames(locale, calendarId, callback, context); default: assert(false); return false; diff --git a/src/corefx/System.Globalization.Native/holders.h b/src/corefx/System.Globalization.Native/holders.h index 0658e551c1..f0d5550a80 100644 --- a/src/corefx/System.Globalization.Native/holders.h +++ b/src/corefx/System.Globalization.Native/holders.h @@ -9,6 +9,7 @@ #include "unicode/udat.h" #include "unicode/unum.h" #include "unicode/uldnames.h" +#include "unicode/ures.h" // IcuHolder is a template that can manage the lifetime of a raw pointer to ensure that it is cleaned up at the correct // time. The general usage pattern is to aquire some ICU resource via an _open call, then construct a holder using the @@ -89,9 +90,18 @@ struct ULocaleDisplayNamesCloser } }; +struct UResourceBundleCloser +{ + void operator()(UResourceBundle* pResourceBundle) const + { + ures_close(pResourceBundle); + } +}; + typedef IcuHolder UCalendarHolder; typedef IcuHolder UEnumerationHolder; typedef IcuHolder UDateTimePatternGeneratorHolder; typedef IcuHolder UDateFormatHolder; typedef IcuHolder UNumberFormatHolder; typedef IcuHolder ULocaleDisplayNamesHolder; +typedef IcuHolder UResourceBundleHolder; -- cgit v1.2.3 From 1f60ac78635b5d73d6b315b1cbd0ff0915e2dac6 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Tue, 20 Oct 2015 14:50:28 -0700 Subject: Remove C++ Locale use in EnumSymbols --- src/corefx/System.Globalization.Native/calendarData.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/corefx/System.Globalization.Native/calendarData.cpp b/src/corefx/System.Globalization.Native/calendarData.cpp index c0940ecf14..c14a9b1a6e 100644 --- a/src/corefx/System.Globalization.Native/calendarData.cpp +++ b/src/corefx/System.Globalization.Native/calendarData.cpp @@ -408,13 +408,14 @@ bool EnumSymbols(Locale& locale, if (U_FAILURE(err)) return false; - Locale localeWithCalendar(locale); - localeWithCalendar.setKeywordValue("calendar", GetCalendarName(calendarId), err); + char localeWithCalendarName[ULOC_FULLNAME_CAPACITY]; + strncpy(localeWithCalendarName, locale.getName(), ULOC_FULLNAME_CAPACITY); + uloc_setKeywordValue("calendar", GetCalendarName(calendarId), localeWithCalendarName, ULOC_FULLNAME_CAPACITY, &err); if (U_FAILURE(err)) return false; - UCalendar* pCalendar = ucal_open(nullptr, 0, localeWithCalendar.getName(), UCAL_DEFAULT, &err); + UCalendar* pCalendar = ucal_open(nullptr, 0, localeWithCalendarName, UCAL_DEFAULT, &err); UCalendarHolder calenderHolder(pCalendar, err); if (U_FAILURE(err)) -- cgit v1.2.3 From 6427d1fb7c1643efe31494b1cbfa122bb588b91b Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Tue, 20 Oct 2015 18:37:54 -0700 Subject: Move off Locale instance methods To prepare for removing icu::Locale in favor of just using the id directly, remove all the uses of Locale methods except for .getName(). We now use GetLocale to create a Locale but then turn it into a char* for all the helper methods. After this change, we can update GetLocale to do locale parsing into a char buffer and remove all the locale.getName() calls with just `locale'. --- .../System.Globalization.Native/calendarData.cpp | 66 ++++++----- .../localeNumberData.cpp | 38 +++--- .../localeStringData.cpp | 127 ++++++++++++++------- 3 files changed, 138 insertions(+), 93 deletions(-) diff --git a/src/corefx/System.Globalization.Native/calendarData.cpp b/src/corefx/System.Globalization.Native/calendarData.cpp index c14a9b1a6e..32f7925af9 100644 --- a/src/corefx/System.Globalization.Native/calendarData.cpp +++ b/src/corefx/System.Globalization.Native/calendarData.cpp @@ -249,10 +249,10 @@ GetMonthDayPattern Gets the Month-Day DateTime pattern for the specified locale. */ -CalendarDataResult GetMonthDayPattern(Locale& locale, UChar* sMonthDay, int32_t stringCapacity) +CalendarDataResult GetMonthDayPattern(const char* locale, UChar* sMonthDay, int32_t stringCapacity) { UErrorCode err = U_ZERO_ERROR; - UDateTimePatternGenerator* pGenerator = udatpg_open(locale.getName(), &err); + UDateTimePatternGenerator* pGenerator = udatpg_open(locale, &err); UDateTimePatternGeneratorHolder generatorHolder(pGenerator, err); if (U_FAILURE(err)) @@ -270,10 +270,10 @@ GetNativeCalendarName Gets the native calendar name. */ CalendarDataResult -GetNativeCalendarName(Locale& locale, CalendarId calendarId, UChar* nativeName, int32_t stringCapacity) +GetNativeCalendarName(const char* locale, CalendarId calendarId, UChar* nativeName, int32_t stringCapacity) { UErrorCode err = U_ZERO_ERROR; - ULocaleDisplayNames* pDisplayNames = uldn_open(locale.getName(), ULDN_STANDARD_NAMES, &err); + ULocaleDisplayNames* pDisplayNames = uldn_open(locale, ULDN_STANDARD_NAMES, &err); ULocaleDisplayNamesHolder displayNamesHolder(pDisplayNames, err); uldn_keyValueDisplayName(pDisplayNames, "calendar", GetCalendarName(calendarId), nativeName, stringCapacity, &err); @@ -298,9 +298,9 @@ extern "C" CalendarDataResult GetCalendarInfo( switch (dataType) { case NativeName: - return GetNativeCalendarName(locale, calendarId, result, resultCapacity); + return GetNativeCalendarName(locale.getName(), calendarId, result, resultCapacity); case MonthDay: - return GetMonthDayPattern(locale, result, resultCapacity); + return GetMonthDayPattern(locale.getName(), result, resultCapacity); default: assert(false); return UnknownError; @@ -314,13 +314,13 @@ InvokeCallbackForDatePattern Gets the ICU date pattern for the specified locale and EStyle and invokes the callback with the result. */ -bool InvokeCallbackForDatePattern(Locale& locale, +bool InvokeCallbackForDatePattern(const char* locale, UDateFormatStyle style, EnumCalendarInfoCallback callback, const void* context) { UErrorCode err = U_ZERO_ERROR; - UDateFormat* pFormat = udat_open(UDAT_NONE, style, locale.getName(), nullptr, 0, nullptr, 0, &err); + UDateFormat* pFormat = udat_open(UDAT_NONE, style, locale, nullptr, 0, nullptr, 0, &err); UDateFormatHolder formatHolder(pFormat, err); if (U_FAILURE(err)) @@ -353,13 +353,13 @@ InvokeCallbackForDateTimePattern Gets the DateTime pattern for the specified skeleton and invokes the callback with the retrieved value. */ -bool InvokeCallbackForDateTimePattern(Locale& locale, +bool InvokeCallbackForDateTimePattern(const char* locale, const UChar* patternSkeleton, EnumCalendarInfoCallback callback, const void* context) { UErrorCode err = U_ZERO_ERROR; - UDateTimePatternGenerator* pGenerator = udatpg_open(locale.getName(), &err); + UDateTimePatternGenerator* pGenerator = udatpg_open(locale, &err); UDateTimePatternGeneratorHolder generatorHolder(pGenerator, err); if (U_FAILURE(err)) @@ -394,7 +394,7 @@ EnumSymbols Enumerates of of the symbols of a type for a locale and calendar and invokes a callback for each value. */ -bool EnumSymbols(Locale& locale, +bool EnumSymbols(const char* locale, CalendarId calendarId, UDateFormatSymbolType type, int32_t startIndex, @@ -402,14 +402,14 @@ bool EnumSymbols(Locale& locale, const void* context) { UErrorCode err = U_ZERO_ERROR; - UDateFormat* pFormat = udat_open(UDAT_DEFAULT, UDAT_DEFAULT, locale.getName(), nullptr, 0, nullptr, 0, &err); + UDateFormat* pFormat = udat_open(UDAT_DEFAULT, UDAT_DEFAULT, locale, nullptr, 0, nullptr, 0, &err); UDateFormatHolder formatHolder(pFormat, err); if (U_FAILURE(err)) return false; char localeWithCalendarName[ULOC_FULLNAME_CAPACITY]; - strncpy(localeWithCalendarName, locale.getName(), ULOC_FULLNAME_CAPACITY); + strncpy(localeWithCalendarName, locale, ULOC_FULLNAME_CAPACITY); uloc_setKeywordValue("calendar", GetCalendarName(calendarId), localeWithCalendarName, ULOC_FULLNAME_CAPACITY, &err); if (U_FAILURE(err)) @@ -471,7 +471,10 @@ EnumAbbrevEraNames Enumerates all the abbreviated era names of the specified locale and calendar, invoking the callback function for each era name. */ -bool EnumAbbrevEraNames(Locale& locale, CalendarId calendarId, EnumCalendarInfoCallback callback, const void* context) +bool EnumAbbrevEraNames(const char* locale, + CalendarId calendarId, + EnumCalendarInfoCallback callback, + const void* context) { // The C-API for ICU provides no way to get at the abbreviated era names for a calendar (so we can't use EnumSymbols // here). Instead we will try to walk the ICU resource tables directly and fall back to regular era names if can't @@ -482,7 +485,7 @@ bool EnumAbbrevEraNames(Locale& locale, CalendarId calendarId, EnumCalendarInfoC char* localeNamePtr = localeNameBuf; char* parentNamePtr = parentNameBuf; - strncpy(localeNamePtr, locale.getName(), ULOC_FULLNAME_CAPACITY); + strncpy(localeNamePtr, locale, ULOC_FULLNAME_CAPACITY); while (true) { @@ -564,37 +567,38 @@ extern "C" int32_t EnumCalendarInfo(EnumCalendarInfoCallback callback, // ShortDates to map kShort and kMedium in ICU, but also adding the "yMd" // skeleton as well, as this // closely matches what is used on Windows - return InvokeCallbackForDateTimePattern(locale, UDAT_YEAR_NUM_MONTH_DAY_UCHAR, callback, context) && - InvokeCallbackForDatePattern(locale, UDAT_SHORT, callback, context) && - InvokeCallbackForDatePattern(locale, UDAT_MEDIUM, callback, context); + return InvokeCallbackForDateTimePattern( + locale.getName(), UDAT_YEAR_NUM_MONTH_DAY_UCHAR, callback, context) && + InvokeCallbackForDatePattern(locale.getName(), UDAT_SHORT, callback, context) && + InvokeCallbackForDatePattern(locale.getName(), UDAT_MEDIUM, callback, context); case LongDates: // LongDates map to kFull and kLong in ICU. - return InvokeCallbackForDatePattern(locale, UDAT_FULL, callback, context) && - InvokeCallbackForDatePattern(locale, UDAT_LONG, callback, context); + return InvokeCallbackForDatePattern(locale.getName(), UDAT_FULL, callback, context) && + InvokeCallbackForDatePattern(locale.getName(), UDAT_LONG, callback, context); case YearMonths: - return InvokeCallbackForDateTimePattern(locale, UDAT_YEAR_MONTH_UCHAR, callback, context); + return InvokeCallbackForDateTimePattern(locale.getName(), UDAT_YEAR_MONTH_UCHAR, callback, context); case DayNames: - return EnumSymbols(locale, calendarId, UDAT_STANDALONE_WEEKDAYS, 1, callback, context); + return EnumSymbols(locale.getName(), calendarId, UDAT_STANDALONE_WEEKDAYS, 1, callback, context); case AbbrevDayNames: - return EnumSymbols(locale, calendarId, UDAT_STANDALONE_SHORT_WEEKDAYS, 1, callback, context); + return EnumSymbols(locale.getName(), calendarId, UDAT_STANDALONE_SHORT_WEEKDAYS, 1, callback, context); case MonthNames: - return EnumSymbols(locale, calendarId, UDAT_STANDALONE_MONTHS, 0, callback, context); + return EnumSymbols(locale.getName(), calendarId, UDAT_STANDALONE_MONTHS, 0, callback, context); case AbbrevMonthNames: - return EnumSymbols(locale, calendarId, UDAT_STANDALONE_SHORT_MONTHS, 0, callback, context); + return EnumSymbols(locale.getName(), calendarId, UDAT_STANDALONE_SHORT_MONTHS, 0, callback, context); case SuperShortDayNames: #ifdef HAVE_DTWIDTHTYPE_SHORT - return EnumSymbols(locale, calendarId, UDAT_STANDALONE_SHORTER_WEEKDAYS, 1, callback, context); + return EnumSymbols(locale.getName(), calendarId, UDAT_STANDALONE_SHORTER_WEEKDAYS, 1, callback, context); #else - return EnumSymbols(locale, calendarId, UDAT_STANDALONE_NARROW_WEEKDAYS, 1, callback, context); + return EnumSymbols(locale.getName(), calendarId, UDAT_STANDALONE_NARROW_WEEKDAYS, 1, callback, context); #endif case MonthGenitiveNames: - return EnumSymbols(locale, calendarId, UDAT_MONTHS, 0, callback, context); + return EnumSymbols(locale.getName(), calendarId, UDAT_MONTHS, 0, callback, context); case AbbrevMonthGenitiveNames: - return EnumSymbols(locale, calendarId, UDAT_SHORT_MONTHS, 0, callback, context); + return EnumSymbols(locale.getName(), calendarId, UDAT_SHORT_MONTHS, 0, callback, context); case EraNames: - return EnumSymbols(locale, calendarId, UDAT_ERAS, 0, callback, context); + return EnumSymbols(locale.getName(), calendarId, UDAT_ERAS, 0, callback, context); case AbbrevEraNames: - return EnumAbbrevEraNames(locale, calendarId, callback, context); + return EnumAbbrevEraNames(locale.getName(), calendarId, callback, context); default: assert(false); return false; diff --git a/src/corefx/System.Globalization.Native/localeNumberData.cpp b/src/corefx/System.Globalization.Native/localeNumberData.cpp index 79dcd78cb3..b73ca1c779 100644 --- a/src/corefx/System.Globalization.Native/localeNumberData.cpp +++ b/src/corefx/System.Globalization.Native/localeNumberData.cpp @@ -214,7 +214,7 @@ GetCurrencyNegativePattern Implementation of NumberFormatInfo.CurrencyNegativePattern. Returns the pattern index. */ -int GetCurrencyNegativePattern(const Locale& locale) +int GetCurrencyNegativePattern(const char* locale) { const int DEFAULT_VALUE = 0; static const char* Patterns[] = {"(Cn)", @@ -235,7 +235,7 @@ int GetCurrencyNegativePattern(const Locale& locale) "(n C)"}; UErrorCode status = U_ZERO_ERROR; - UNumberFormat* pFormat = unum_open(UNUM_CURRENCY, nullptr, 0, locale.getName(), nullptr, &status); + UNumberFormat* pFormat = unum_open(UNUM_CURRENCY, nullptr, 0, locale, nullptr, &status); UNumberFormatHolder formatHolder(pFormat, status); assert(U_SUCCESS(status)); @@ -259,13 +259,13 @@ GetCurrencyPositivePattern Implementation of NumberFormatInfo.CurrencyPositivePattern. Returns the pattern index. */ -int GetCurrencyPositivePattern(const Locale& locale) +int GetCurrencyPositivePattern(const char* locale) { const int DEFAULT_VALUE = 0; static const char* Patterns[] = {"Cn", "nC", "C n", "n C"}; UErrorCode status = U_ZERO_ERROR; - UNumberFormat* pFormat = unum_open(UNUM_CURRENCY, nullptr, 0, locale.getName(), nullptr, &status); + UNumberFormat* pFormat = unum_open(UNUM_CURRENCY, nullptr, 0, locale, nullptr, &status); UNumberFormatHolder formatHolder(pFormat, status); assert(U_SUCCESS(status)); @@ -289,13 +289,13 @@ GetNumberNegativePattern Implementation of NumberFormatInfo.NumberNegativePattern. Returns the pattern index. */ -int GetNumberNegativePattern(const Locale& locale) +int GetNumberNegativePattern(const char* locale) { const int DEFAULT_VALUE = 1; static const char* Patterns[] = {"(n)", "-n", "- n", "n-", "n -"}; UErrorCode status = U_ZERO_ERROR; - UNumberFormat* pFormat = unum_open(UNUM_DECIMAL, nullptr, 0, locale.getName(), nullptr, &status); + UNumberFormat* pFormat = unum_open(UNUM_DECIMAL, nullptr, 0, locale, nullptr, &status); UNumberFormatHolder formatHolder(pFormat, status); assert(U_SUCCESS(status)); @@ -319,14 +319,14 @@ GetPercentNegativePattern Implementation of NumberFormatInfo.PercentNegativePattern. Returns the pattern index. */ -int GetPercentNegativePattern(const Locale& locale) +int GetPercentNegativePattern(const char* locale) { const int DEFAULT_VALUE = 0; static const char* Patterns[] = { "-n %", "-n%", "-%n", "%-n", "%n-", "n-%", "n%-", "-% n", "n %-", "% n-", "% -n", "n- %"}; UErrorCode status = U_ZERO_ERROR; - UNumberFormat* pFormat = unum_open(UNUM_PERCENT, nullptr, 0, locale.getName(), nullptr, &status); + UNumberFormat* pFormat = unum_open(UNUM_PERCENT, nullptr, 0, locale, nullptr, &status); UNumberFormatHolder formatHolder(pFormat, status); assert(U_SUCCESS(status)); @@ -350,13 +350,13 @@ GetPercentPositivePattern Implementation of NumberFormatInfo.PercentPositivePattern. Returns the pattern index. */ -int GetPercentPositivePattern(const Locale& locale) +int GetPercentPositivePattern(const char* locale) { const int DEFAULT_VALUE = 0; static const char* Patterns[] = {"n %", "n%", "%n", "% n"}; UErrorCode status = U_ZERO_ERROR; - UNumberFormat* pFormat = unum_open(UNUM_PERCENT, nullptr, 0, locale.getName(), nullptr, &status); + UNumberFormat* pFormat = unum_open(UNUM_PERCENT, nullptr, 0, locale, nullptr, &status); UNumberFormatHolder formatHolder(pFormat, status); assert(U_SUCCESS(status)); @@ -380,11 +380,11 @@ GetMeasurementSystem Obtains the measurement system for the local, determining if US or metric. Returns 1 for US, 0 otherwise. */ -UErrorCode GetMeasurementSystem(const char* localeId, int32_t* value) +UErrorCode GetMeasurementSystem(const char* locale, int32_t* value) { UErrorCode status = U_ZERO_ERROR; - UMeasurementSystem measurementSystem = ulocdata_getMeasurementSystem(localeId, &status); + UMeasurementSystem measurementSystem = ulocdata_getMeasurementSystem(locale, &status); if (U_SUCCESS(status)) { *value = (measurementSystem == UMeasurementSystem::UMS_US) ? 1 : 0; @@ -413,7 +413,7 @@ extern "C" int32_t GetLocaleInfoInt(const UChar* localeName, LocaleNumberData lo switch (localeNumberData) { case LanguageId: - *value = locale.getLCID(); + *value = uloc_getLCID(locale.getName()); break; case MeasurementSystem: status = GetMeasurementSystem(locale.getName(), value); @@ -429,7 +429,7 @@ extern "C" int32_t GetLocaleInfoInt(const UChar* localeName, LocaleNumberData lo break; } case NegativeNumberFormat: - *value = GetNumberNegativePattern(locale); + *value = GetNumberNegativePattern(locale.getName()); break; case MonetaryFractionalDigitsCount: { @@ -442,10 +442,10 @@ extern "C" int32_t GetLocaleInfoInt(const UChar* localeName, LocaleNumberData lo break; } case PositiveMonetaryNumberFormat: - *value = GetCurrencyPositivePattern(locale); + *value = GetCurrencyPositivePattern(locale.getName()); break; case NegativeMonetaryNumberFormat: - *value = GetCurrencyNegativePattern(locale); + *value = GetCurrencyNegativePattern(locale.getName()); break; case FirstWeekOfYear: { @@ -483,7 +483,7 @@ extern "C" int32_t GetLocaleInfoInt(const UChar* localeName, LocaleNumberData lo // 0 - Left to right (such as en-US) // 1 - Right to left (such as arabic locales) ULayoutType orientation = uloc_getCharacterOrientation(locale.getName(), &status); - // alternative implementation in ICU 54+ is Locale.isRightToLeft() which + // alternative implementation in ICU 54+ is uloc_isRightToLeft() which // also supports script tags in locale if (U_SUCCESS(status)) { @@ -503,10 +503,10 @@ extern "C" int32_t GetLocaleInfoInt(const UChar* localeName, LocaleNumberData lo break; } case NegativePercentFormat: - *value = GetPercentNegativePattern(locale); + *value = GetPercentNegativePattern(locale.getName()); break; case PositivePercentFormat: - *value = GetPercentPositivePattern(locale); + *value = GetPercentPositivePattern(locale.getName()); break; default: status = U_UNSUPPORTED_ERROR; diff --git a/src/corefx/System.Globalization.Native/localeStringData.cpp b/src/corefx/System.Globalization.Native/localeStringData.cpp index b0a5cf9a00..fb3dff812d 100644 --- a/src/corefx/System.Globalization.Native/localeStringData.cpp +++ b/src/corefx/System.Globalization.Native/localeStringData.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "locale.hpp" #include "holders.h" @@ -55,10 +56,10 @@ GetLocaleInfoDecimalFormatSymbol Obtains the value of a DecimalFormatSymbols */ UErrorCode -GetLocaleInfoDecimalFormatSymbol(const Locale& locale, UNumberFormatSymbol symbol, UChar* value, int32_t valueLength) +GetLocaleInfoDecimalFormatSymbol(const char* locale, UNumberFormatSymbol symbol, UChar* value, int32_t valueLength) { UErrorCode status = U_ZERO_ERROR; - UNumberFormat* pFormat = unum_open(UNUM_DECIMAL, nullptr, 0, locale.getName(), nullptr, &status); + UNumberFormat* pFormat = unum_open(UNUM_DECIMAL, nullptr, 0, locale, nullptr, &status); UNumberFormatHolder formatHolder(pFormat, status); if (U_FAILURE(status)) @@ -77,7 +78,7 @@ GetDigitSymbol Obtains the value of a Digit DecimalFormatSymbols */ -UErrorCode GetDigitSymbol(const Locale& locale, +UErrorCode GetDigitSymbol(const char* locale, UErrorCode previousStatus, UNumberFormatSymbol symbol, int digit, @@ -98,10 +99,10 @@ GetLocaleInfoAmPm Obtains the value of the AM or PM string for a locale. */ -UErrorCode GetLocaleInfoAmPm(const Locale& locale, bool am, UChar* value, int32_t valueLength) +UErrorCode GetLocaleInfoAmPm(const char* locale, bool am, UChar* value, int32_t valueLength) { UErrorCode status = U_ZERO_ERROR; - UDateFormat* pFormat = udat_open(UDAT_DEFAULT, UDAT_DEFAULT, locale.getName(), nullptr, 0, nullptr, 0, &status); + UDateFormat* pFormat = udat_open(UDAT_DEFAULT, UDAT_DEFAULT, locale, nullptr, 0, nullptr, 0, &status); UDateFormatHolder formatHolder(pFormat, status); if (U_FAILURE(status)) @@ -114,6 +115,54 @@ UErrorCode GetLocaleInfoAmPm(const Locale& locale, bool am, UChar* value, int32_ return status; } +/* +Function: +GetLocaleIso639LanguageName + +Gets the language name for a locale (via uloc_getLanguage) and converts the result to UChars +*/ +UErrorCode GetLocaleIso639LanguageName(const char* locale, UChar* value, int32_t valueLength) +{ + UErrorCode status = U_ZERO_ERROR; + int32_t length = uloc_getLanguage(locale, nullptr, 0, &status); + + std::vector buf(length + 1, '\0'); + status = U_ZERO_ERROR; + + uloc_getLanguage(locale, buf.data(), length + 1, &status); + + if (U_SUCCESS(status)) + { + status = u_charsToUChars_safe(buf.data(), value, valueLength); + } + + return status; +} + +/* +Function: +GetLocaleIso3166CountryName + +Gets the country name for a locale (via uloc_getCountry) and converts the result to UChars +*/ +UErrorCode GetLocaleIso3166CountryName(const char* locale, UChar* value, int32_t valueLength) +{ + UErrorCode status = U_ZERO_ERROR; + int32_t length = uloc_getCountry(locale, nullptr, 0, &status); + + std::vector buf(length + 1, '\0'); + status = U_ZERO_ERROR; + + uloc_getCountry(locale, buf.data(), length + 1, &status); + + if (U_SUCCESS(status)) + { + status = u_charsToUChars_safe(buf.data(), value, valueLength); + } + + return status; +} + /* PAL Function: GetLocaleInfoString @@ -130,98 +179,90 @@ GetLocaleInfoString(const UChar* localeName, LocaleStringData localeStringData, return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); } - UnicodeString str; UErrorCode status = U_ZERO_ERROR; switch (localeStringData) { case LocalizedDisplayName: - locale.getDisplayName(str); - str.extract(value, valueLength, status); + uloc_getDisplayName(locale.getName(), uloc_getDefault(), value, valueLength, &status); break; case EnglishDisplayName: - locale.getDisplayName(Locale::getEnglish(), str); - str.extract(value, valueLength, status); + uloc_getDisplayName(locale.getName(), ULOC_ENGLISH, value, valueLength, &status); break; case NativeDisplayName: - locale.getDisplayName(locale, str); - str.extract(value, valueLength, status); + uloc_getDisplayName(locale.getName(), locale.getName(), value, valueLength, &status); break; case LocalizedLanguageName: - locale.getDisplayLanguage(str); - str.extract(value, valueLength, status); + uloc_getDisplayLanguage(locale.getName(), uloc_getDefault(), value, valueLength, &status); break; case EnglishLanguageName: - locale.getDisplayLanguage(Locale::getEnglish(), str); - str.extract(value, valueLength, status); + uloc_getDisplayLanguage(locale.getName(), ULOC_ENGLISH, value, valueLength, &status); break; case NativeLanguageName: - locale.getDisplayLanguage(locale, str); - str.extract(value, valueLength, status); + uloc_getDisplayLanguage(locale.getName(), locale.getName(), value, valueLength, &status); break; case EnglishCountryName: - locale.getDisplayCountry(Locale::getEnglish(), str); - str.extract(value, valueLength, status); + uloc_getDisplayCountry(locale.getName(), ULOC_ENGLISH, value, valueLength, &status); break; case NativeCountryName: - locale.getDisplayCountry(locale, str); - str.extract(value, valueLength, status); + uloc_getDisplayCountry(locale.getName(), locale.getName(), value, valueLength, &status); break; case ListSeparator: // fall through case ThousandSeparator: - status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_GROUPING_SEPARATOR_SYMBOL, value, valueLength); + status = + GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_GROUPING_SEPARATOR_SYMBOL, value, valueLength); break; case DecimalSeparator: - status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_DECIMAL_SEPARATOR_SYMBOL, value, valueLength); + status = + GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_DECIMAL_SEPARATOR_SYMBOL, value, valueLength); break; case Digits: - status = GetDigitSymbol(locale, status, UNUM_ZERO_DIGIT_SYMBOL, 0, value, valueLength); + status = GetDigitSymbol(locale.getName(), status, UNUM_ZERO_DIGIT_SYMBOL, 0, value, valueLength); // symbols UNUM_ONE_DIGIT to UNUM_NINE_DIGIT are contiguous for (int32_t symbol = UNUM_ONE_DIGIT_SYMBOL; symbol <= UNUM_NINE_DIGIT_SYMBOL; symbol++) { int charIndex = symbol - UNUM_ONE_DIGIT_SYMBOL + 1; status = GetDigitSymbol( - locale, status, static_cast(symbol), charIndex, value, valueLength); + locale.getName(), status, static_cast(symbol), charIndex, value, valueLength); } break; case MonetarySymbol: - status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_CURRENCY_SYMBOL, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_CURRENCY_SYMBOL, value, valueLength); break; case Iso4217MonetarySymbol: - status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_INTL_CURRENCY_SYMBOL, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_INTL_CURRENCY_SYMBOL, value, valueLength); break; case MonetaryDecimalSeparator: - status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MONETARY_SEPARATOR_SYMBOL, value, valueLength); + status = + GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_MONETARY_SEPARATOR_SYMBOL, value, valueLength); break; case MonetaryThousandSeparator: - status = - GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol( + locale.getName(), UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL, value, valueLength); break; case AMDesignator: - status = GetLocaleInfoAmPm(locale, true, value, valueLength); + status = GetLocaleInfoAmPm(locale.getName(), true, value, valueLength); break; case PMDesignator: - status = GetLocaleInfoAmPm(locale, false, value, valueLength); + status = GetLocaleInfoAmPm(locale.getName(), false, value, valueLength); break; case PositiveSign: - status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PLUS_SIGN_SYMBOL, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_PLUS_SIGN_SYMBOL, value, valueLength); break; case NegativeSign: - status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MINUS_SIGN_SYMBOL, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_MINUS_SIGN_SYMBOL, value, valueLength); break; case Iso639LanguageName: - status = u_charsToUChars_safe(locale.getLanguage(), value, valueLength); + status = GetLocaleIso639LanguageName(locale.getName(), value, valueLength); break; case Iso3166CountryName: - // coreclr expects 2-character version, not 3 (3 would correspond to - // LOCALE_SISO3166CTRYNAME2 and locale.getISO3Country) - status = u_charsToUChars_safe(locale.getCountry(), value, valueLength); + status = GetLocaleIso3166CountryName(locale.getName(), value, valueLength); break; case NaNSymbol: - status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_NAN_SYMBOL, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_NAN_SYMBOL, value, valueLength); break; case PositiveInfinitySymbol: - status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_INFINITY_SYMBOL, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_INFINITY_SYMBOL, value, valueLength); break; case ParentName: { @@ -241,10 +282,10 @@ GetLocaleInfoString(const UChar* localeName, LocaleStringData localeStringData, break; } case PercentSymbol: - status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PERCENT_SYMBOL, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_PERCENT_SYMBOL, value, valueLength); break; case PerMilleSymbol: - status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PERMILL_SYMBOL, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_PERMILL_SYMBOL, value, valueLength); break; default: status = U_UNSUPPORTED_ERROR; -- cgit v1.2.3 From 0b3b276ea837e3ae9720e72142fe5c0ae54ad5a3 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Tue, 20 Oct 2015 19:30:42 -0700 Subject: Remove use of icu::Locale C++ type Remove all the uses of the icu::Locale type in favor of just using a char* which is the raw locale id (which is exactly what all the ICU C apis use for a locale). The meat of this change si in locale.cpp to actually handle doing the conversion from UChar* to char*. The rest of the places are dealing with the fallout (GetLocale now has a different signiture and the .getName() dance is no longer needed as we have a raw locale name all the time now). --- .../System.Globalization.Native/calendarData.cpp | 61 ++++++----- src/corefx/System.Globalization.Native/locale.cpp | 118 ++++++++++++++------- src/corefx/System.Globalization.Native/locale.hpp | 8 +- .../localeNumberData.cpp | 43 ++++---- .../localeStringData.cpp | 77 +++++++------- 5 files changed, 179 insertions(+), 128 deletions(-) diff --git a/src/corefx/System.Globalization.Native/calendarData.cpp b/src/corefx/System.Globalization.Native/calendarData.cpp index 32f7925af9..744f4528f8 100644 --- a/src/corefx/System.Globalization.Native/calendarData.cpp +++ b/src/corefx/System.Globalization.Native/calendarData.cpp @@ -209,12 +209,14 @@ Returns the list of CalendarIds that are available for the specified locale. */ extern "C" int32_t GetCalendars(const UChar* localeName, CalendarId* calendars, int32_t calendarsCapacity) { - Locale locale = GetLocale(localeName); - if (locale.isBogus()) + UErrorCode err = U_ZERO_ERROR; + char locale[ULOC_FULLNAME_CAPACITY]; + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &err); + + if (U_FAILURE(err)) return 0; - UErrorCode err = U_ZERO_ERROR; - UEnumeration* pEnum = ucal_getKeywordValuesForLocale("calendar", locale.getName(), TRUE, &err); + UEnumeration* pEnum = ucal_getKeywordValuesForLocale("calendar", locale, TRUE, &err); UEnumerationHolder enumHolder(pEnum, err); if (U_FAILURE(err)) @@ -291,16 +293,19 @@ with the requested value. extern "C" CalendarDataResult GetCalendarInfo( const UChar* localeName, CalendarId calendarId, CalendarDataType dataType, UChar* result, int32_t resultCapacity) { - Locale locale = GetLocale(localeName); - if (locale.isBogus()) + UErrorCode err = U_ZERO_ERROR; + char locale[ULOC_FULLNAME_CAPACITY]; + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &err); + + if (U_FAILURE(err)) return UnknownError; switch (dataType) { case NativeName: - return GetNativeCalendarName(locale.getName(), calendarId, result, resultCapacity); + return GetNativeCalendarName(locale, calendarId, result, resultCapacity); case MonthDay: - return GetMonthDayPattern(locale.getName(), result, resultCapacity); + return GetMonthDayPattern(locale, result, resultCapacity); default: assert(false); return UnknownError; @@ -557,8 +562,11 @@ extern "C" int32_t EnumCalendarInfo(EnumCalendarInfoCallback callback, CalendarDataType dataType, const void* context) { - Locale locale = GetLocale(localeName); - if (locale.isBogus()) + UErrorCode err = U_ZERO_ERROR; + char locale[ULOC_FULLNAME_CAPACITY]; + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &err); + + if (U_FAILURE(err)) return false; switch (dataType) @@ -567,38 +575,37 @@ extern "C" int32_t EnumCalendarInfo(EnumCalendarInfoCallback callback, // ShortDates to map kShort and kMedium in ICU, but also adding the "yMd" // skeleton as well, as this // closely matches what is used on Windows - return InvokeCallbackForDateTimePattern( - locale.getName(), UDAT_YEAR_NUM_MONTH_DAY_UCHAR, callback, context) && - InvokeCallbackForDatePattern(locale.getName(), UDAT_SHORT, callback, context) && - InvokeCallbackForDatePattern(locale.getName(), UDAT_MEDIUM, callback, context); + return InvokeCallbackForDateTimePattern(locale, UDAT_YEAR_NUM_MONTH_DAY_UCHAR, callback, context) && + InvokeCallbackForDatePattern(locale, UDAT_SHORT, callback, context) && + InvokeCallbackForDatePattern(locale, UDAT_MEDIUM, callback, context); case LongDates: // LongDates map to kFull and kLong in ICU. - return InvokeCallbackForDatePattern(locale.getName(), UDAT_FULL, callback, context) && - InvokeCallbackForDatePattern(locale.getName(), UDAT_LONG, callback, context); + return InvokeCallbackForDatePattern(locale, UDAT_FULL, callback, context) && + InvokeCallbackForDatePattern(locale, UDAT_LONG, callback, context); case YearMonths: - return InvokeCallbackForDateTimePattern(locale.getName(), UDAT_YEAR_MONTH_UCHAR, callback, context); + return InvokeCallbackForDateTimePattern(locale, UDAT_YEAR_MONTH_UCHAR, callback, context); case DayNames: - return EnumSymbols(locale.getName(), calendarId, UDAT_STANDALONE_WEEKDAYS, 1, callback, context); + return EnumSymbols(locale, calendarId, UDAT_STANDALONE_WEEKDAYS, 1, callback, context); case AbbrevDayNames: - return EnumSymbols(locale.getName(), calendarId, UDAT_STANDALONE_SHORT_WEEKDAYS, 1, callback, context); + return EnumSymbols(locale, calendarId, UDAT_STANDALONE_SHORT_WEEKDAYS, 1, callback, context); case MonthNames: - return EnumSymbols(locale.getName(), calendarId, UDAT_STANDALONE_MONTHS, 0, callback, context); + return EnumSymbols(locale, calendarId, UDAT_STANDALONE_MONTHS, 0, callback, context); case AbbrevMonthNames: - return EnumSymbols(locale.getName(), calendarId, UDAT_STANDALONE_SHORT_MONTHS, 0, callback, context); + return EnumSymbols(locale, calendarId, UDAT_STANDALONE_SHORT_MONTHS, 0, callback, context); case SuperShortDayNames: #ifdef HAVE_DTWIDTHTYPE_SHORT - return EnumSymbols(locale.getName(), calendarId, UDAT_STANDALONE_SHORTER_WEEKDAYS, 1, callback, context); + return EnumSymbols(locale, calendarId, UDAT_STANDALONE_SHORTER_WEEKDAYS, 1, callback, context); #else - return EnumSymbols(locale.getName(), calendarId, UDAT_STANDALONE_NARROW_WEEKDAYS, 1, callback, context); + return EnumSymbols(locale, calendarId, UDAT_STANDALONE_NARROW_WEEKDAYS, 1, callback, context); #endif case MonthGenitiveNames: - return EnumSymbols(locale.getName(), calendarId, UDAT_MONTHS, 0, callback, context); + return EnumSymbols(locale, calendarId, UDAT_MONTHS, 0, callback, context); case AbbrevMonthGenitiveNames: - return EnumSymbols(locale.getName(), calendarId, UDAT_SHORT_MONTHS, 0, callback, context); + return EnumSymbols(locale, calendarId, UDAT_SHORT_MONTHS, 0, callback, context); case EraNames: - return EnumSymbols(locale.getName(), calendarId, UDAT_ERAS, 0, callback, context); + return EnumSymbols(locale, calendarId, UDAT_ERAS, 0, callback, context); case AbbrevEraNames: - return EnumAbbrevEraNames(locale.getName(), calendarId, callback, context); + return EnumAbbrevEraNames(locale, calendarId, callback, context); default: assert(false); return false; diff --git a/src/corefx/System.Globalization.Native/locale.cpp b/src/corefx/System.Globalization.Native/locale.cpp index f71b68d554..c8a78f86e4 100644 --- a/src/corefx/System.Globalization.Native/locale.cpp +++ b/src/corefx/System.Globalization.Native/locale.cpp @@ -31,45 +31,76 @@ int32_t UErrorCodeToBool(UErrorCode status) return 0; } -Locale GetLocale(const UChar* localeName, bool canonize) +int32_t GetLocale( + const UChar* localeName, char* localeNameResult, int32_t localeNameResultLength, bool canonicalize, UErrorCode* err) { - char localeNameTemp[ULOC_FULLNAME_CAPACITY]; + char localeNameTemp[ULOC_FULLNAME_CAPACITY] = {0}; + int32_t localeLength; - if (localeName != NULL) + // Convert ourselves instead of doing u_UCharsToChars as that function considers '@' a variant and stops. + for (int i = 0; i < ULOC_FULLNAME_CAPACITY - 1; i++) { - // use UnicodeString.extract instead of u_UCharsToChars; u_UCharsToChars - // considers '@' a variant and stops - UnicodeString str(localeName, -1, ULOC_FULLNAME_CAPACITY); - str.extract(0, str.length(), localeNameTemp); + UChar c = localeName[i]; + + if (c > (UChar)0x7F) + { + *err = U_ILLEGAL_ARGUMENT_ERROR; + return ULOC_FULLNAME_CAPACITY; + } + + localeNameTemp[i] = (char)c; + + if (c == (UChar)0x0) + { + break; + } } - Locale loc; - if (canonize) + if (canonicalize) { - loc = Locale::createCanonical(localeName == NULL ? NULL : localeNameTemp); + localeLength = uloc_canonicalize(localeNameTemp, localeNameResult, localeNameResultLength, err); } else { - loc = Locale::createFromName(localeName == NULL ? NULL : localeNameTemp); + localeLength = uloc_getName(localeNameTemp, localeNameResult, localeNameResultLength, err); + } + + if (U_SUCCESS(*err)) + { + // Make sure the "language" part of the locale is reasonable (i.e. we can fetch it and it is within range). + // This mimics how the C++ ICU API determines if a locale is "bogus" or not. + + char language[ULOC_LANG_CAPACITY]; + uloc_getLanguage(localeNameTemp, language, ULOC_LANG_CAPACITY, err); + + if (*err == U_STRING_NOT_TERMINATED_WARNING) + { + // ULOC_LANG_CAPACITY includes the null terminator, so if we couldn't extract the language with the null + // terminator, the language must be invalid. + + *err = U_ILLEGAL_ARGUMENT_ERROR; + } } - return loc; + return localeLength; } UErrorCode u_charsToUChars_safe(const char* str, UChar* value, int32_t valueLength) { int len = strlen(str); + if (len >= valueLength) { return U_BUFFER_OVERFLOW_ERROR; } + u_charsToUChars(str, value, len + 1); return U_ZERO_ERROR; } -int FixupLocaleName(UChar* value, int32_t valueLength) +int32_t FixupLocaleName(UChar* value, int32_t valueLength) { - int i = 0; + int32_t i = 0; for (; i < valueLength; i++) { if (value[i] == (UChar)'\0') @@ -87,20 +118,19 @@ int FixupLocaleName(UChar* value, int32_t valueLength) extern "C" int32_t GetLocaleName(const UChar* localeName, UChar* value, int32_t valueLength) { - Locale locale = GetLocale(localeName, true); - - if (locale.isBogus()) - { - // localeName not properly formatted - return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); - } + UErrorCode status = U_ZERO_ERROR; - // other validation done on managed side + char localeNameBuffer[ULOC_FULLNAME_CAPACITY]; + GetLocale(localeName, localeNameBuffer, ULOC_FULLNAME_CAPACITY, true, &status); - UErrorCode status = u_charsToUChars_safe(locale.getName(), value, valueLength); if (U_SUCCESS(status)) { - FixupLocaleName(value, valueLength); + status = u_charsToUChars_safe(localeNameBuffer, value, valueLength); + + if (U_SUCCESS(status)) + { + FixupLocaleName(value, valueLength); + } } return UErrorCodeToBool(status); @@ -108,29 +138,35 @@ extern "C" int32_t GetLocaleName(const UChar* localeName, UChar* value, int32_t extern "C" int32_t GetDefaultLocaleName(UChar* value, int32_t valueLength) { - Locale locale = GetLocale(NULL); - if (locale.isBogus()) - { - // ICU should be able to get default locale - return UErrorCodeToBool(U_INTERNAL_PROGRAM_ERROR); - } + char localeNameBuffer[ULOC_FULLNAME_CAPACITY]; + UErrorCode status = U_ZERO_ERROR; + + const char* defaultLocale = uloc_getDefault(); + + uloc_getBaseName(defaultLocale, localeNameBuffer, ULOC_FULLNAME_CAPACITY, &status); - UErrorCode status = u_charsToUChars_safe(locale.getBaseName(), value, valueLength); if (U_SUCCESS(status)) { - int localeNameLen = FixupLocaleName(value, valueLength); + status = u_charsToUChars_safe(localeNameBuffer, value, valueLength); - // if collation is present, return that to managed side - char collationValueTemp[ULOC_KEYWORDS_CAPACITY]; - if (locale.getKeywordValue("collation", collationValueTemp, ULOC_KEYWORDS_CAPACITY, status) > 0) + if (U_SUCCESS(status)) { - // copy the collation; managed uses a "_" to represent collation (not - // "@collation=") - status = u_charsToUChars_safe("_", &value[localeNameLen], valueLength - localeNameLen); - if (U_SUCCESS(status)) + int localeNameLen = FixupLocaleName(value, valueLength); + + char collationValueTemp[ULOC_KEYWORDS_CAPACITY]; + int32_t collationLen = + uloc_getKeywordValue(defaultLocale, "collation", collationValueTemp, ULOC_KEYWORDS_CAPACITY, &status); + + if (U_SUCCESS(status) && collationLen > 0) { - status = u_charsToUChars_safe( - collationValueTemp, &value[localeNameLen + 1], valueLength - localeNameLen - 1); + // copy the collation; managed uses a "_" to represent collation (not + // "@collation=") + status = u_charsToUChars_safe("_", &value[localeNameLen], valueLength - localeNameLen); + if (U_SUCCESS(status)) + { + status = u_charsToUChars_safe( + collationValueTemp, &value[localeNameLen + 1], valueLength - localeNameLen - 1); + } } } } diff --git a/src/corefx/System.Globalization.Native/locale.hpp b/src/corefx/System.Globalization.Native/locale.hpp index 3ea1707c05..d6b61b7db6 100644 --- a/src/corefx/System.Globalization.Native/locale.hpp +++ b/src/corefx/System.Globalization.Native/locale.hpp @@ -27,9 +27,13 @@ int32_t UErrorCodeToBool(UErrorCode code); Function: GetLocale -Returns a locale given the locale name +Converts a managed localeName into something ICU understands and can use as a localeName. */ -Locale GetLocale(const UChar* localeName, bool canonize = false); +int32_t GetLocale(const UChar* localeName, + char* localeNameResult, + int32_t localeNameResultLength, + bool canonicalize, + UErrorCode* err); /* Function: diff --git a/src/corefx/System.Globalization.Native/localeNumberData.cpp b/src/corefx/System.Globalization.Native/localeNumberData.cpp index b73ca1c779..842bcffac2 100644 --- a/src/corefx/System.Globalization.Native/localeNumberData.cpp +++ b/src/corefx/System.Globalization.Native/localeNumberData.cpp @@ -402,25 +402,26 @@ Returns 1 for success, 0 otherwise */ extern "C" int32_t GetLocaleInfoInt(const UChar* localeName, LocaleNumberData localeNumberData, int32_t* value) { - Locale locale = GetLocale(localeName); - if (locale.isBogus()) + UErrorCode status = U_ZERO_ERROR; + char locale[ULOC_FULLNAME_CAPACITY]; + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &status); + + if (U_FAILURE(status)) { return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); } - UErrorCode status = U_ZERO_ERROR; - switch (localeNumberData) { case LanguageId: - *value = uloc_getLCID(locale.getName()); + *value = uloc_getLCID(locale); break; case MeasurementSystem: - status = GetMeasurementSystem(locale.getName(), value); + status = GetMeasurementSystem(locale, value); break; case FractionalDigitsCount: { - UNumberFormat* numformat = unum_open(UNUM_DECIMAL, NULL, 0, locale.getName(), NULL, &status); + UNumberFormat* numformat = unum_open(UNUM_DECIMAL, NULL, 0, locale, NULL, &status); if (U_SUCCESS(status)) { *value = unum_getAttribute(numformat, UNUM_MAX_FRACTION_DIGITS); @@ -429,11 +430,11 @@ extern "C" int32_t GetLocaleInfoInt(const UChar* localeName, LocaleNumberData lo break; } case NegativeNumberFormat: - *value = GetNumberNegativePattern(locale.getName()); + *value = GetNumberNegativePattern(locale); break; case MonetaryFractionalDigitsCount: { - UNumberFormat* numformat = unum_open(UNUM_CURRENCY, NULL, 0, locale.getName(), NULL, &status); + UNumberFormat* numformat = unum_open(UNUM_CURRENCY, NULL, 0, locale, NULL, &status); if (U_SUCCESS(status)) { *value = unum_getAttribute(numformat, UNUM_MAX_FRACTION_DIGITS); @@ -442,15 +443,15 @@ extern "C" int32_t GetLocaleInfoInt(const UChar* localeName, LocaleNumberData lo break; } case PositiveMonetaryNumberFormat: - *value = GetCurrencyPositivePattern(locale.getName()); + *value = GetCurrencyPositivePattern(locale); break; case NegativeMonetaryNumberFormat: - *value = GetCurrencyNegativePattern(locale.getName()); + *value = GetCurrencyNegativePattern(locale); break; case FirstWeekOfYear: { // corresponds to DateTimeFormat.CalendarWeekRule - UCalendar* pCal = ucal_open(nullptr, 0, locale.getName(), UCAL_TRADITIONAL, &status); + UCalendar* pCal = ucal_open(nullptr, 0, locale, UCAL_TRADITIONAL, &status); UCalendarHolder calHolder(pCal, status); if (U_SUCCESS(status)) @@ -482,7 +483,7 @@ extern "C" int32_t GetLocaleInfoInt(const UChar* localeName, LocaleNumberData lo // used in coreclr) // 0 - Left to right (such as en-US) // 1 - Right to left (such as arabic locales) - ULayoutType orientation = uloc_getCharacterOrientation(locale.getName(), &status); + ULayoutType orientation = uloc_getCharacterOrientation(locale, &status); // alternative implementation in ICU 54+ is uloc_isRightToLeft() which // also supports script tags in locale if (U_SUCCESS(status)) @@ -493,7 +494,7 @@ extern "C" int32_t GetLocaleInfoInt(const UChar* localeName, LocaleNumberData lo } case FirstDayofWeek: { - UCalendar* pCal = ucal_open(nullptr, 0, locale.getName(), UCAL_TRADITIONAL, &status); + UCalendar* pCal = ucal_open(nullptr, 0, locale, UCAL_TRADITIONAL, &status); UCalendarHolder calHolder(pCal, status); if (U_SUCCESS(status)) @@ -503,10 +504,10 @@ extern "C" int32_t GetLocaleInfoInt(const UChar* localeName, LocaleNumberData lo break; } case NegativePercentFormat: - *value = GetPercentNegativePattern(locale.getName()); + *value = GetPercentNegativePattern(locale); break; case PositivePercentFormat: - *value = GetPercentPositivePattern(locale.getName()); + *value = GetPercentPositivePattern(locale); break; default: status = U_UNSUPPORTED_ERROR; @@ -529,8 +530,11 @@ extern "C" int32_t GetLocaleInfoGroupingSizes(const UChar* localeName, int32_t* primaryGroupSize, int32_t* secondaryGroupSize) { - Locale locale = GetLocale(localeName); - if (locale.isBogus()) + UErrorCode status = U_ZERO_ERROR; + char locale[ULOC_FULLNAME_CAPACITY]; + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &status); + + if (U_FAILURE(status)) { return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); } @@ -548,8 +552,7 @@ extern "C" int32_t GetLocaleInfoGroupingSizes(const UChar* localeName, return UErrorCodeToBool(U_UNSUPPORTED_ERROR); } - UErrorCode status = U_ZERO_ERROR; - UNumberFormat* numformat = unum_open(style, NULL, 0, locale.getName(), NULL, &status); + UNumberFormat* numformat = unum_open(style, NULL, 0, locale, NULL, &status); if (U_SUCCESS(status)) { *primaryGroupSize = unum_getAttribute(numformat, UNUM_GROUPING_SIZE); diff --git a/src/corefx/System.Globalization.Native/localeStringData.cpp b/src/corefx/System.Globalization.Native/localeStringData.cpp index fb3dff812d..6c7942f97c 100644 --- a/src/corefx/System.Globalization.Native/localeStringData.cpp +++ b/src/corefx/System.Globalization.Native/localeStringData.cpp @@ -173,96 +173,95 @@ Returns 1 for success, 0 otherwise extern "C" int32_t GetLocaleInfoString(const UChar* localeName, LocaleStringData localeStringData, UChar* value, int32_t valueLength) { - Locale locale = GetLocale(localeName); - if (locale.isBogus()) + UErrorCode status = U_ZERO_ERROR; + char locale[ULOC_FULLNAME_CAPACITY]; + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &status); + + if (U_FAILURE(status)) { return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); } - UErrorCode status = U_ZERO_ERROR; switch (localeStringData) { case LocalizedDisplayName: - uloc_getDisplayName(locale.getName(), uloc_getDefault(), value, valueLength, &status); + uloc_getDisplayName(locale, uloc_getDefault(), value, valueLength, &status); break; case EnglishDisplayName: - uloc_getDisplayName(locale.getName(), ULOC_ENGLISH, value, valueLength, &status); + uloc_getDisplayName(locale, ULOC_ENGLISH, value, valueLength, &status); break; case NativeDisplayName: - uloc_getDisplayName(locale.getName(), locale.getName(), value, valueLength, &status); + uloc_getDisplayName(locale, locale, value, valueLength, &status); break; case LocalizedLanguageName: - uloc_getDisplayLanguage(locale.getName(), uloc_getDefault(), value, valueLength, &status); + uloc_getDisplayLanguage(locale, uloc_getDefault(), value, valueLength, &status); break; case EnglishLanguageName: - uloc_getDisplayLanguage(locale.getName(), ULOC_ENGLISH, value, valueLength, &status); + uloc_getDisplayLanguage(locale, ULOC_ENGLISH, value, valueLength, &status); break; case NativeLanguageName: - uloc_getDisplayLanguage(locale.getName(), locale.getName(), value, valueLength, &status); + uloc_getDisplayLanguage(locale, locale, value, valueLength, &status); break; case EnglishCountryName: - uloc_getDisplayCountry(locale.getName(), ULOC_ENGLISH, value, valueLength, &status); + uloc_getDisplayCountry(locale, ULOC_ENGLISH, value, valueLength, &status); break; case NativeCountryName: - uloc_getDisplayCountry(locale.getName(), locale.getName(), value, valueLength, &status); + uloc_getDisplayCountry(locale, locale, value, valueLength, &status); break; case ListSeparator: // fall through case ThousandSeparator: - status = - GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_GROUPING_SEPARATOR_SYMBOL, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_GROUPING_SEPARATOR_SYMBOL, value, valueLength); break; case DecimalSeparator: - status = - GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_DECIMAL_SEPARATOR_SYMBOL, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_DECIMAL_SEPARATOR_SYMBOL, value, valueLength); break; case Digits: - status = GetDigitSymbol(locale.getName(), status, UNUM_ZERO_DIGIT_SYMBOL, 0, value, valueLength); + status = GetDigitSymbol(locale, status, UNUM_ZERO_DIGIT_SYMBOL, 0, value, valueLength); // symbols UNUM_ONE_DIGIT to UNUM_NINE_DIGIT are contiguous for (int32_t symbol = UNUM_ONE_DIGIT_SYMBOL; symbol <= UNUM_NINE_DIGIT_SYMBOL; symbol++) { int charIndex = symbol - UNUM_ONE_DIGIT_SYMBOL + 1; status = GetDigitSymbol( - locale.getName(), status, static_cast(symbol), charIndex, value, valueLength); + locale, status, static_cast(symbol), charIndex, value, valueLength); } break; case MonetarySymbol: - status = GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_CURRENCY_SYMBOL, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_CURRENCY_SYMBOL, value, valueLength); break; case Iso4217MonetarySymbol: - status = GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_INTL_CURRENCY_SYMBOL, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_INTL_CURRENCY_SYMBOL, value, valueLength); break; case MonetaryDecimalSeparator: - status = - GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_MONETARY_SEPARATOR_SYMBOL, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MONETARY_SEPARATOR_SYMBOL, value, valueLength); break; case MonetaryThousandSeparator: - status = GetLocaleInfoDecimalFormatSymbol( - locale.getName(), UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL, value, valueLength); + status = + GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL, value, valueLength); break; case AMDesignator: - status = GetLocaleInfoAmPm(locale.getName(), true, value, valueLength); + status = GetLocaleInfoAmPm(locale, true, value, valueLength); break; case PMDesignator: - status = GetLocaleInfoAmPm(locale.getName(), false, value, valueLength); + status = GetLocaleInfoAmPm(locale, false, value, valueLength); break; case PositiveSign: - status = GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_PLUS_SIGN_SYMBOL, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PLUS_SIGN_SYMBOL, value, valueLength); break; case NegativeSign: - status = GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_MINUS_SIGN_SYMBOL, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MINUS_SIGN_SYMBOL, value, valueLength); break; case Iso639LanguageName: - status = GetLocaleIso639LanguageName(locale.getName(), value, valueLength); + status = GetLocaleIso639LanguageName(locale, value, valueLength); break; case Iso3166CountryName: - status = GetLocaleIso3166CountryName(locale.getName(), value, valueLength); + status = GetLocaleIso3166CountryName(locale, value, valueLength); break; case NaNSymbol: - status = GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_NAN_SYMBOL, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_NAN_SYMBOL, value, valueLength); break; case PositiveInfinitySymbol: - status = GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_INFINITY_SYMBOL, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_INFINITY_SYMBOL, value, valueLength); break; case ParentName: { @@ -270,7 +269,7 @@ GetLocaleInfoString(const UChar* localeName, LocaleStringData localeStringData, // including invariant locale char localeNameTemp[ULOC_FULLNAME_CAPACITY]; - uloc_getParent(locale.getName(), localeNameTemp, ULOC_FULLNAME_CAPACITY, &status); + uloc_getParent(locale, localeNameTemp, ULOC_FULLNAME_CAPACITY, &status); if (U_SUCCESS(status)) { status = u_charsToUChars_safe(localeNameTemp, value, valueLength); @@ -282,10 +281,10 @@ GetLocaleInfoString(const UChar* localeName, LocaleStringData localeStringData, break; } case PercentSymbol: - status = GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_PERCENT_SYMBOL, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PERCENT_SYMBOL, value, valueLength); break; case PerMilleSymbol: - status = GetLocaleInfoDecimalFormatSymbol(locale.getName(), UNUM_PERMILL_SYMBOL, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PERMILL_SYMBOL, value, valueLength); break; default: status = U_UNSUPPORTED_ERROR; @@ -304,15 +303,17 @@ Returns 1 for success, 0 otherwise */ extern "C" int32_t GetLocaleTimeFormat(const UChar* localeName, int shortFormat, UChar* value, int32_t valueLength) { - Locale locale = GetLocale(localeName); - if (locale.isBogus()) + UErrorCode err = U_ZERO_ERROR; + char locale[ULOC_FULLNAME_CAPACITY]; + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &err); + + if (U_FAILURE(err)) { return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); } - UErrorCode err = U_ZERO_ERROR; UDateFormatStyle style = (shortFormat != 0) ? UDAT_SHORT : UDAT_MEDIUM; - UDateFormat* pFormat = udat_open(style, UDAT_NONE, locale.getName(), nullptr, 0, nullptr, 0, &err); + UDateFormat* pFormat = udat_open(style, UDAT_NONE, locale, nullptr, 0, nullptr, 0, &err); UDateFormatHolder formatHolder(pFormat, err); if (U_FAILURE(err)) -- cgit v1.2.3 From b3efdce6526c351589f2262d655d9739519aed8f Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Tue, 20 Oct 2015 22:18:29 -0700 Subject: Cleanup include directives --- src/corefx/System.Globalization.Native/calendarData.cpp | 5 ----- src/corefx/System.Globalization.Native/holders.h | 14 +++++++------- src/corefx/System.Globalization.Native/locale.cpp | 5 ----- .../System.Globalization.Native/localeNumberData.cpp | 8 ++------ .../System.Globalization.Native/localeStringData.cpp | 5 ----- 5 files changed, 9 insertions(+), 28 deletions(-) diff --git a/src/corefx/System.Globalization.Native/calendarData.cpp b/src/corefx/System.Globalization.Native/calendarData.cpp index 744f4528f8..54fd471d71 100644 --- a/src/corefx/System.Globalization.Native/calendarData.cpp +++ b/src/corefx/System.Globalization.Native/calendarData.cpp @@ -10,11 +10,6 @@ #include "locale.hpp" #include "holders.h" -#include -#include -#include -#include - #define GREGORIAN_NAME "gregorian" #define JAPANESE_NAME "japanese" #define BUDDHIST_NAME "buddhist" diff --git a/src/corefx/System.Globalization.Native/holders.h b/src/corefx/System.Globalization.Native/holders.h index f0d5550a80..3e081893f4 100644 --- a/src/corefx/System.Globalization.Native/holders.h +++ b/src/corefx/System.Globalization.Native/holders.h @@ -3,13 +3,13 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -#include "unicode/ucal.h" -#include "unicode/uenum.h" -#include "unicode/udatpg.h" -#include "unicode/udat.h" -#include "unicode/unum.h" -#include "unicode/uldnames.h" -#include "unicode/ures.h" +#include +#include +#include +#include +#include +#include +#include // IcuHolder is a template that can manage the lifetime of a raw pointer to ensure that it is cleaned up at the correct // time. The general usage pattern is to aquire some ICU resource via an _open call, then construct a holder using the diff --git a/src/corefx/System.Globalization.Native/locale.cpp b/src/corefx/System.Globalization.Native/locale.cpp index c8a78f86e4..6ae699a107 100644 --- a/src/corefx/System.Globalization.Native/locale.cpp +++ b/src/corefx/System.Globalization.Native/locale.cpp @@ -10,11 +10,6 @@ #include "locale.hpp" -#include "unicode/dcfmtsym.h" //decimal -#include "unicode/dtfmtsym.h" //date -#include "unicode/localpointer.h" -#include "unicode/ulocdata.h" - int32_t UErrorCodeToBool(UErrorCode status) { if (U_SUCCESS(status)) diff --git a/src/corefx/System.Globalization.Native/localeNumberData.cpp b/src/corefx/System.Globalization.Native/localeNumberData.cpp index 842bcffac2..b7bb95a48c 100644 --- a/src/corefx/System.Globalization.Native/localeNumberData.cpp +++ b/src/corefx/System.Globalization.Native/localeNumberData.cpp @@ -8,15 +8,11 @@ #include #include +#include + #include "locale.hpp" #include "holders.h" -#include "unicode/calendar.h" -#include "unicode/decimfmt.h" -#include "unicode/localpointer.h" -#include "unicode/numfmt.h" -#include "unicode/ulocdata.h" - // invariant character definitions used by ICU #define UCHAR_CURRENCY ((UChar)0x00A4) // international currency #define UCHAR_SPACE ((UChar)0x0020) // space diff --git a/src/corefx/System.Globalization.Native/localeStringData.cpp b/src/corefx/System.Globalization.Native/localeStringData.cpp index 6c7942f97c..8e115129c2 100644 --- a/src/corefx/System.Globalization.Native/localeStringData.cpp +++ b/src/corefx/System.Globalization.Native/localeStringData.cpp @@ -11,11 +11,6 @@ #include "locale.hpp" #include "holders.h" -#include "unicode/dcfmtsym.h" //decimal symbols -#include "unicode/dtfmtsym.h" //date symbols -#include "unicode/smpdtfmt.h" //date format -#include "unicode/localpointer.h" - // Enum that corresponds to managed enum CultureData.LocaleStringData. // The numeric values of the enum members match their Win32 counterparts. enum LocaleStringData : int32_t -- cgit v1.2.3 From 806dea821e3f02f7e3da9f0d9a9f6aaf4929cef8 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Wed, 21 Oct 2015 11:20:48 -0700 Subject: Hygine cleanups in holders.h Use "= delete" syntax to make it clear the IcuHolder copy constructor and assignment opperators are removed. Remove superfluous "public" modifier on the struct closers used by the IcuHolders. --- src/corefx/System.Globalization.Native/holders.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/corefx/System.Globalization.Native/holders.h b/src/corefx/System.Globalization.Native/holders.h index 3e081893f4..9176de3b20 100644 --- a/src/corefx/System.Globalization.Native/holders.h +++ b/src/corefx/System.Globalization.Native/holders.h @@ -34,13 +34,12 @@ class IcuHolder private: T* m_p; - IcuHolder(const IcuHolder&); - IcuHolder operator=(const IcuHolder&); + IcuHolder(const IcuHolder&) = delete; + IcuHolder operator=(const IcuHolder&) = delete; }; struct UCalendarCloser { - public: void operator()(UCalendar* pCal) const { ucal_close(pCal); @@ -49,7 +48,6 @@ struct UCalendarCloser struct UEnumerationCloser { - public: void operator()(UEnumeration* pEnum) const { uenum_close(pEnum); @@ -58,7 +56,6 @@ struct UEnumerationCloser struct UDateTimePatternGeneratorCloser { - public: void operator()(UDateTimePatternGenerator* pGenerator) const { udatpg_close(pGenerator); @@ -67,7 +64,6 @@ struct UDateTimePatternGeneratorCloser struct UDateFormatCloser { - public: void operator()(UDateFormat* pDateFormat) const { udat_close(pDateFormat); -- cgit v1.2.3 From f17e90cb25573fbc7894725ccd008a2fb116236f Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Wed, 21 Oct 2015 13:48:37 -0700 Subject: Link against libicucore on OSX OSX ships with a copy of ICU (their globalization APIs are built on top of it). Since we only use stable c based APIs, we can link against it using the methods described in using a System ICU in the ICU User's Guide (basically we disable function renaming, don't use C++ and only use stable APIs). The ICU headers are not part of the SDK, so we continue to need ICU installed via Homebrew as a build time dependency. Fixes dotnet/corefx#3849 --- .../System.Globalization.Native/CMakeLists.txt | 45 +++++++++++++++------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/src/corefx/System.Globalization.Native/CMakeLists.txt b/src/corefx/System.Globalization.Native/CMakeLists.txt index 04f29fced7..a4e232d4b9 100644 --- a/src/corefx/System.Globalization.Native/CMakeLists.txt +++ b/src/corefx/System.Globalization.Native/CMakeLists.txt @@ -9,16 +9,25 @@ add_definitions(-DBIT64=1) set(ICU_HOMEBREW_LIB_PATH "/usr/local/opt/icu4c/lib") set(ICU_HOMEBREW_INC_PATH "/usr/local/opt/icu4c/include") -find_library(ICUUC NAMES icuuc PATHS ${ICU_HOMEBREW_LIB_PATH}) -if(ICUUC STREQUAL ICUUC-NOTFOUND) - message(FATAL_ERROR "Cannot find libicuuc, try installing libicu-dev (or the appropriate package for your platform)") - return() -endif() - -find_library(ICUI18N NAMES icui18n PATHS ${ICU_HOMEBREW_LIB_PATH}) -if(ICUI18N STREQUAL ICUI18N-NOTFOUND) - message(FATAL_ERROR "Cannot find libicui18n, try installing libicu-dev (or the appropriate package for your platform)") - return() +if(NOT CLR_CMAKE_PLATFORM_DARWIN) + find_library(ICUUC NAMES icuuc PATHS ${ICU_HOMEBREW_LIB_PATH}) + if(ICUUC STREQUAL ICUUC-NOTFOUND) + message(FATAL_ERROR "Cannot find libicuuc, try installing libicu-dev (or the appropriate package for your platform)") + return() + endif() + + find_library(ICUI18N NAMES icui18n PATHS ${ICU_HOMEBREW_LIB_PATH}) + if(ICUI18N STREQUAL ICUI18N-NOTFOUND) + message(FATAL_ERROR "Cannot find libicui18n, try installing libicu-dev (or the appropriate package for your platform)") + return() + endif() + +else() + find_library(ICUCORE NAMES icucore) + if(ICUI18N STREQUAL ICUCORE-NOTFOUND) + message(FATAL_ERROR "Cannot find libicucore, skipping build for System.Globalization.Native. .NET globalization is not expected to function.") + return() + endif() endif() find_path(UTYPES_H "unicode/utypes.h" PATHS ${ICU_HOMEBREW_INC_PATH}) @@ -61,9 +70,17 @@ add_library(System.Globalization.Native # Disable the "lib" prefix. set_target_properties(System.Globalization.Native PROPERTIES PREFIX "") -target_link_libraries(System.Globalization.Native - ${ICUUC} - ${ICUI18N} -) +if(NOT CLR_CMAKE_PLATFORM_DARWIN) + target_link_libraries(System.Globalization.Native + ${ICUUC} + ${ICUI18N} + ) +else() + target_link_libraries(System.Globalization.Native + ${ICUCORE} + ) + + add_definitions(-DU_DISABLE_RENAMING=1) +endif() install (TARGETS System.Globalization.Native DESTINATION .) -- cgit v1.2.3 From 26e874722bebb95e27b9ce2fba14812b885aaf19 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Thu, 22 Oct 2015 17:46:54 -0700 Subject: Use std::vector instead of calloc This matches what we do in other places in calendarData.cpp, the RAII pattern will make it easier to not leak memory. --- .../System.Globalization.Native/calendarData.cpp | 24 ++++++---------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src/corefx/System.Globalization.Native/calendarData.cpp b/src/corefx/System.Globalization.Native/calendarData.cpp index 54fd471d71..6e971d89ef 100644 --- a/src/corefx/System.Globalization.Native/calendarData.cpp +++ b/src/corefx/System.Globalization.Native/calendarData.cpp @@ -329,20 +329,15 @@ bool InvokeCallbackForDatePattern(const char* locale, UErrorCode ignore = U_ZERO_ERROR; int32_t patternLen = udat_toPattern(pFormat, false, nullptr, 0, &ignore); - UChar* pattern = (UChar*)calloc(patternLen + 1, sizeof(UChar)); + std::vector pattern(patternLen + 1, '\0'); - if (pattern == nullptr) - return false; - - udat_toPattern(pFormat, false, pattern, patternLen + 1, &err); + udat_toPattern(pFormat, false, pattern.data(), patternLen + 1, &err); if (U_SUCCESS(err)) { - callback(pattern, context); + callback(pattern.data(), context); } - free(pattern); - return U_SUCCESS(err); } @@ -368,22 +363,15 @@ bool InvokeCallbackForDateTimePattern(const char* locale, UErrorCode ignore = U_ZERO_ERROR; int32_t patternLen = udatpg_getBestPattern(pGenerator, patternSkeleton, -1, nullptr, 0, &ignore); - UChar* bestPattern = (UChar*)calloc(patternLen + 1, sizeof(UChar)); - - if (bestPattern == nullptr) - { - return false; - } + std::vector bestPattern(patternLen + 1, '\0'); - udatpg_getBestPattern(pGenerator, patternSkeleton, -1, bestPattern, patternLen + 1, &err); + udatpg_getBestPattern(pGenerator, patternSkeleton, -1, bestPattern.data(), patternLen + 1, &err); if (U_SUCCESS(err)) { - callback(bestPattern, context); + callback(bestPattern.data(), context); } - free(bestPattern); - return U_SUCCESS(err); } -- cgit v1.2.3 From 036964efe7ec495e26dade9aed9b847e1c566d6a Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Fri, 23 Oct 2015 00:55:23 -0700 Subject: Use correct close function for UNumberFormat --- src/corefx/System.Globalization.Native/holders.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corefx/System.Globalization.Native/holders.h b/src/corefx/System.Globalization.Native/holders.h index 9176de3b20..4969726ed6 100644 --- a/src/corefx/System.Globalization.Native/holders.h +++ b/src/corefx/System.Globalization.Native/holders.h @@ -74,7 +74,7 @@ struct UNumberFormatCloser { void operator()(UNumberFormat* pNumberFormat) const { - udat_close(pNumberFormat); + unum_close(pNumberFormat); } }; -- cgit v1.2.3 From 398dc12ed5b19cdb116e06c84762ad64ffb88612 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Fri, 23 Oct 2015 14:23:55 -0700 Subject: Fix spelling issues --- src/corefx/System.Globalization.Native/calendarData.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corefx/System.Globalization.Native/calendarData.cpp b/src/corefx/System.Globalization.Native/calendarData.cpp index 6e971d89ef..aba9e7c8fb 100644 --- a/src/corefx/System.Globalization.Native/calendarData.cpp +++ b/src/corefx/System.Globalization.Native/calendarData.cpp @@ -379,7 +379,7 @@ bool InvokeCallbackForDateTimePattern(const char* locale, Function: EnumSymbols -Enumerates of of the symbols of a type for a locale and calendar and invokes a callback +Enumerates all of the symbols of a type for a locale and calendar and invokes a callback for each value. */ bool EnumSymbols(const char* locale, @@ -404,7 +404,7 @@ bool EnumSymbols(const char* locale, return false; UCalendar* pCalendar = ucal_open(nullptr, 0, localeWithCalendarName, UCAL_DEFAULT, &err); - UCalendarHolder calenderHolder(pCalendar, err); + UCalendarHolder calendarHolder(pCalendar, err); if (U_FAILURE(err)) return false; -- cgit v1.2.3 From 392f5f43475843a8dc417ef84b88e855e91f909e Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Fri, 23 Oct 2015 14:24:13 -0700 Subject: Cleanup CMakeLists.txt There were a few problems that needed to be addressed: - Our detection logic around testing if ICU supported a feature was still checking for C++ stuff instead of the coresponding C code (which we ended up using). - There was some cleanup we could do now that the OSX and other Unix builds were split apart --- .../System.Globalization.Native/CMakeLists.txt | 42 ++++++++++++---------- .../System.Globalization.Native/calendarData.cpp | 5 ++- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/corefx/System.Globalization.Native/CMakeLists.txt b/src/corefx/System.Globalization.Native/CMakeLists.txt index a4e232d4b9..08d35a0053 100644 --- a/src/corefx/System.Globalization.Native/CMakeLists.txt +++ b/src/corefx/System.Globalization.Native/CMakeLists.txt @@ -6,45 +6,49 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) add_definitions(-DPIC=1) add_definitions(-DBIT64=1) -set(ICU_HOMEBREW_LIB_PATH "/usr/local/opt/icu4c/lib") set(ICU_HOMEBREW_INC_PATH "/usr/local/opt/icu4c/include") +find_path(UTYPES_H "unicode/utypes.h" PATHS ${ICU_HOMEBREW_INC_PATH}) +if(UTYPES_H STREQUAL UTYPES_H-NOTFOUND) + message(FATAL_ERROR "Cannont find utypes.h, try installing libicu-dev (or the appropriate package for your platform)") + return() +endif() + if(NOT CLR_CMAKE_PLATFORM_DARWIN) - find_library(ICUUC NAMES icuuc PATHS ${ICU_HOMEBREW_LIB_PATH}) + find_library(ICUUC icuuc) if(ICUUC STREQUAL ICUUC-NOTFOUND) message(FATAL_ERROR "Cannot find libicuuc, try installing libicu-dev (or the appropriate package for your platform)") return() endif() - find_library(ICUI18N NAMES icui18n PATHS ${ICU_HOMEBREW_LIB_PATH}) + find_library(ICUI18N icui18n) if(ICUI18N STREQUAL ICUI18N-NOTFOUND) message(FATAL_ERROR "Cannot find libicui18n, try installing libicu-dev (or the appropriate package for your platform)") return() endif() + set(CMAKE_REQUIRED_INCLUDES ${ICU_HOMEBREW_INC_PATH}) + CHECK_CXX_SOURCE_COMPILES(" + #include + int main() { UDateFormatSymbolType e = UDAT_STANDALONE_SHORTER_WEEKDAYS; } + " HAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS) + + if(HAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS) + add_definitions(-DHAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS=1) + endif(HAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS) + else() - find_library(ICUCORE NAMES icucore) + + find_library(ICUCORE icucore) if(ICUI18N STREQUAL ICUCORE-NOTFOUND) message(FATAL_ERROR "Cannot find libicucore, skipping build for System.Globalization.Native. .NET globalization is not expected to function.") return() endif() -endif() - -find_path(UTYPES_H "unicode/utypes.h" PATHS ${ICU_HOMEBREW_INC_PATH}) -if(UTYPES_H STREQUAL UTYPES_H-NOTFOUND) - message(FATAL_ERROR "Cannont find utypes.h, try installing libicu-dev (or the appropriate package for your platform)") - return() -endif() -set(CMAKE_REQUIRED_INCLUDES ${ICU_HOMEBREW_INC_PATH}) -CHECK_CXX_SOURCE_COMPILES(" - #include - int main() { DateFormatSymbols::DtWidthType e = DateFormatSymbols::DtWidthType::SHORT; } -" HAVE_DTWIDTHTYPE_SHORT) + # libicucore supports UDAT_STANDALONE_SHORTER_WEEKDAYS + add_definitions(-DHAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS=1) -if(HAVE_DTWIDTHTYPE_SHORT) - add_definitions(-DHAVE_DTWIDTHTYPE_SHORT=1) -endif(HAVE_DTWIDTHTYPE_SHORT) +endif() add_compile_options(-fPIC) diff --git a/src/corefx/System.Globalization.Native/calendarData.cpp b/src/corefx/System.Globalization.Native/calendarData.cpp index aba9e7c8fb..c18bc9de8e 100644 --- a/src/corefx/System.Globalization.Native/calendarData.cpp +++ b/src/corefx/System.Globalization.Native/calendarData.cpp @@ -576,7 +576,10 @@ extern "C" int32_t EnumCalendarInfo(EnumCalendarInfoCallback callback, case AbbrevMonthNames: return EnumSymbols(locale, calendarId, UDAT_STANDALONE_SHORT_MONTHS, 0, callback, context); case SuperShortDayNames: -#ifdef HAVE_DTWIDTHTYPE_SHORT + // UDAT_STANDALONE_SHORTER_WEEKDAYS was added in ICU 51, and CentOS 7 currently uses ICU 50. + // fallback to UDAT_STANDALONE_NARROW_WEEKDAYS in that case. + +#ifdef HAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS return EnumSymbols(locale, calendarId, UDAT_STANDALONE_SHORTER_WEEKDAYS, 1, callback, context); #else return EnumSymbols(locale, calendarId, UDAT_STANDALONE_NARROW_WEEKDAYS, 1, callback, context); -- cgit v1.2.3