From 4a8b474e7777b962a23ab45ec459ba87c5a19e30 Mon Sep 17 00:00:00 2001 From: Jeff Genovy <29107334+jefgen@users.noreply.github.com> Date: Mon, 17 Sep 2018 14:33:08 -0700 Subject: [PATCH] ICU-12973 Enable UWP version of ICU to use Environment variable ICU_ENABLE_TENTATIVE_ERA for testing placeholder names (#124) - Enable UWP version of ICU to use Environment variable ICU_ENABLE_TENTATIVE_ERA for testing placeholder era names. - Use LocalArray for the Era Start Dates to simply memory management, so that goto can be removed. - Also fix some minor typos in header file. --- icu4c/source/i18n/erarules.cpp | 39 ++++++++++++---------------- icu4c/source/i18n/erarules.h | 14 ++++++++-- icu4c/source/i18n/japancal.cpp | 12 +++++++-- icu4c/source/i18n/unicode/calendar.h | 8 +++--- 4 files changed, 43 insertions(+), 30 deletions(-) diff --git a/icu4c/source/i18n/erarules.cpp b/icu4c/source/i18n/erarules.cpp index 3ea385046d2..a05ee280b2b 100644 --- a/icu4c/source/i18n/erarules.cpp +++ b/icu4c/source/i18n/erarules.cpp @@ -99,13 +99,13 @@ static int32_t compareEncodedDateWithYMD(int encoded, int year, int month, int d } } -EraRules::EraRules(int32_t *startDates, int32_t numEras) - : startDates(startDates), numEras(numEras) { +EraRules::EraRules(LocalArray& eraStartDates, int32_t numEras) + : numEras(numEras) { + startDates.moveFrom(eraStartDates); initCurrentEra(); } EraRules::~EraRules() { - uprv_free(startDates); } EraRules* EraRules::createInstance(const char *calType, UBool includeTentativeEra, UErrorCode& status) { @@ -116,7 +116,7 @@ EraRules* EraRules::createInstance(const char *calType, UBool includeTentativeEr ures_getByKey(rb.getAlias(), "calendarData", rb.getAlias(), &status); ures_getByKey(rb.getAlias(), calType, rb.getAlias(), &status); ures_getByKey(rb.getAlias(), "eras", rb.getAlias(), &status); - + if (U_FAILURE(status)) { return nullptr; } @@ -124,33 +124,32 @@ EraRules* EraRules::createInstance(const char *calType, UBool includeTentativeEr int32_t numEras = ures_getSize(rb.getAlias()); int32_t firstTentativeIdx = MAX_INT32; - int32_t *startDates = (int32_t*)uprv_malloc(numEras * sizeof(int32_t)); - if (startDates == nullptr) { - status = U_MEMORY_ALLOCATION_ERROR; + LocalArray startDates(new int32_t[numEras], status); + if (U_FAILURE(status)) { return nullptr; } - uprv_memset(startDates, 0, numEras * sizeof(int32_t)); + uprv_memset(startDates.getAlias(), 0 , numEras * sizeof(int32_t)); while (ures_hasNext(rb.getAlias())) { LocalUResourceBundlePointer eraRuleRes(ures_getNextResource(rb.getAlias(), nullptr, &status)); if (U_FAILURE(status)) { - goto error; + return nullptr; } const char *eraIdxStr = ures_getKey(eraRuleRes.getAlias()); char *endp; int32_t eraIdx = (int32_t)strtol(eraIdxStr, &endp, 10); if ((size_t)(endp - eraIdxStr) != uprv_strlen(eraIdxStr)) { status = U_INVALID_FORMAT_ERROR; - goto error; + return nullptr; } if (eraIdx < 0 || eraIdx >= numEras) { status = U_INVALID_FORMAT_ERROR; - goto error; + return nullptr; } if (isSet(startDates[eraIdx])) { // start date of the index was already set status = U_INVALID_FORMAT_ERROR; - goto error; + return nullptr; } UBool hasName = TRUE; @@ -159,17 +158,17 @@ EraRules* EraRules::createInstance(const char *calType, UBool includeTentativeEr while (ures_hasNext(eraRuleRes.getAlias())) { LocalUResourceBundlePointer res(ures_getNextResource(eraRuleRes.getAlias(), nullptr, &status)); if (U_FAILURE(status)) { - goto error; + return nullptr; } const char *key = ures_getKey(res.getAlias()); if (uprv_strcmp(key, "start") == 0) { const int32_t *fields = ures_getIntVector(res.getAlias(), &len, &status); if (U_FAILURE(status)) { - goto error; + return nullptr; } if (len != 3 || !isValidRuleStartDate(fields[0], fields[1], fields[2])) { status = U_INVALID_FORMAT_ERROR; - goto error; + return nullptr; } startDates[eraIdx] = encodeDate(fields[0], fields[1], fields[2]); } else if (uprv_strcmp(key, "named") == 0) { @@ -193,20 +192,20 @@ EraRules* EraRules::createInstance(const char *calType, UBool includeTentativeEr // This implementation does not support end only rule for eras other than // the first one. status = U_INVALID_FORMAT_ERROR; - goto error; + return nullptr; } U_ASSERT(eraIdx == 0); startDates[eraIdx] = MIN_ENCODED_START; } else { status = U_INVALID_FORMAT_ERROR; - goto error; + return nullptr; } } if (hasName) { if (eraIdx >= firstTentativeIdx) { status = U_INVALID_FORMAT_ERROR; - goto error; + return nullptr; } } else { if (eraIdx < firstTentativeIdx) { @@ -226,10 +225,6 @@ EraRules* EraRules::createInstance(const char *calType, UBool includeTentativeEr status = U_MEMORY_ALLOCATION_ERROR; } return result; - -error: - uprv_free(startDates); - return nullptr; } void EraRules::getStartDate(int32_t eraIdx, int32_t (&fields)[3], UErrorCode& status) const { diff --git a/icu4c/source/i18n/erarules.h b/icu4c/source/i18n/erarules.h index 83a8a82cc37..281420a5aa5 100644 --- a/icu4c/source/i18n/erarules.h +++ b/icu4c/source/i18n/erarules.h @@ -12,6 +12,16 @@ U_NAMESPACE_BEGIN +// Export an explicit template instantiation of LocalArray used as a data member of EraRules. +// When building DLLs for Windows this is required even though no direct access leaks out of the i18n library. +// See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples. +#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN +// Ignore warning 4661 as LocalPointerBase does not use operator== or operator!= +#pragma warning(suppress: 4661) +template class U_I18N_API LocalPointerBase; +template class U_I18N_API LocalArray; +#endif + class U_I18N_API EraRules : public UMemory { public: ~EraRules(); @@ -66,11 +76,11 @@ public: } private: - EraRules(int32_t *startDates, int32_t numEra); + EraRules(LocalArray& eraStartDates, int32_t numEra); void initCurrentEra(); - int32_t *startDates; + LocalArray startDates; int32_t numEras; int32_t currentEra; }; diff --git a/icu4c/source/i18n/japancal.cpp b/icu4c/source/i18n/japancal.cpp index 35e1834098d..5159be337c2 100644 --- a/icu4c/source/i18n/japancal.cpp +++ b/icu4c/source/i18n/japancal.cpp @@ -59,11 +59,19 @@ static void U_CALLCONV initializeEras(UErrorCode &status) { // By default, such tentative era is disabled. // 1. Environment variable ICU_ENABLE_TENTATIVE_ERA=true or false - // 2. Windows registry (TBD) UBool includeTentativeEra = FALSE; -#if U_PLATFORM_HAS_WINUWP_API == 0 +#if U_PLATFORM_HAS_WINUWP_API == 1 + // UWP doesn't allow access to getenv(), but we can call GetEnvironmentVariableW to do the same thing. + UChar varName[26] = {}; + u_charsToUChars(TENTATIVE_ERA_VAR_NAME, varName, static_cast(uprv_strlen(TENTATIVE_ERA_VAR_NAME))); + WCHAR varValue[5] = {}; + DWORD ret = GetEnvironmentVariableW(reinterpret_cast(varName), varValue, UPRV_LENGTHOF(varValue)); + if ((ret == 4) && (_wcsicmp(varValue, L"true") == 0)) { + includeTentativeEra = TRUE; + } +#else char *envVarVal = getenv(TENTATIVE_ERA_VAR_NAME); if (envVarVal != NULL && uprv_stricmp(envVarVal, "true") == 0) { includeTentativeEra = TRUE; diff --git a/icu4c/source/i18n/unicode/calendar.h b/icu4c/source/i18n/unicode/calendar.h index e961c1c6494..023cf053f25 100644 --- a/icu4c/source/i18n/unicode/calendar.h +++ b/icu4c/source/i18n/unicode/calendar.h @@ -130,7 +130,7 @@ class BasicTimeZone; * * **Note:** for some non-Gregorian calendars, different * fields may be necessary for complete disambiguation. For example, a full - * specification of the historial Arabic astronomical calendar requires year, + * specification of the historical Arabic astronomical calendar requires year, * month, day-of-month *and* day-of-week in some cases. * * **Note:** There are certain possible ambiguities in @@ -886,7 +886,7 @@ public: /** * Sets the behavior for handling wall time repeating multiple times * at negative time zone offset transitions. For example, 1:30 AM on - * November 6, 2011 in US Eastern time (Ameirca/New_York) occurs twice; + * November 6, 2011 in US Eastern time (America/New_York) occurs twice; * 1:30 AM EDT, then 1:30 AM EST one hour later. When UCAL_WALLTIME_FIRST * is used, the wall time 1:30AM in this example will be interpreted as 1:30 AM EDT * (first occurrence). When UCAL_WALLTIME_LAST is used, it will be @@ -2152,7 +2152,7 @@ private: TimeZone* fZone; /** - * Option for rpeated wall time + * Option for repeated wall time * @see #setRepeatedWallTimeOption */ UCalendarWallTimeOption fRepeatedWallTime; @@ -2437,7 +2437,7 @@ private: BasicTimeZone* getBasicTimeZone() const; /** - * Find the previous zone transtion near the given time. + * Find the previous zone transition near the given time. * @param base The base time, inclusive * @param transitionTime Receives the result time * @param status The error status