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<int32_t> for the Era Start Dates to simply memory management, so that goto can be removed.
- Also fix some minor typos in header file.
This commit is contained in:
Jeff Genovy 2018-09-17 14:33:08 -07:00 committed by Shane Carr
parent ce92011aff
commit 4a8b474e77
No known key found for this signature in database
GPG Key ID: FCED3B24AAB18B5C
4 changed files with 43 additions and 30 deletions

View File

@ -99,13 +99,13 @@ static int32_t compareEncodedDateWithYMD(int encoded, int year, int month, int d
} }
} }
EraRules::EraRules(int32_t *startDates, int32_t numEras) EraRules::EraRules(LocalArray<int32_t>& eraStartDates, int32_t numEras)
: startDates(startDates), numEras(numEras) { : numEras(numEras) {
startDates.moveFrom(eraStartDates);
initCurrentEra(); initCurrentEra();
} }
EraRules::~EraRules() { EraRules::~EraRules() {
uprv_free(startDates);
} }
EraRules* EraRules::createInstance(const char *calType, UBool includeTentativeEra, UErrorCode& status) { EraRules* EraRules::createInstance(const char *calType, UBool includeTentativeEra, UErrorCode& status) {
@ -124,33 +124,32 @@ EraRules* EraRules::createInstance(const char *calType, UBool includeTentativeEr
int32_t numEras = ures_getSize(rb.getAlias()); int32_t numEras = ures_getSize(rb.getAlias());
int32_t firstTentativeIdx = MAX_INT32; int32_t firstTentativeIdx = MAX_INT32;
int32_t *startDates = (int32_t*)uprv_malloc(numEras * sizeof(int32_t)); LocalArray<int32_t> startDates(new int32_t[numEras], status);
if (startDates == nullptr) { if (U_FAILURE(status)) {
status = U_MEMORY_ALLOCATION_ERROR;
return nullptr; return nullptr;
} }
uprv_memset(startDates, 0, numEras * sizeof(int32_t)); uprv_memset(startDates.getAlias(), 0 , numEras * sizeof(int32_t));
while (ures_hasNext(rb.getAlias())) { while (ures_hasNext(rb.getAlias())) {
LocalUResourceBundlePointer eraRuleRes(ures_getNextResource(rb.getAlias(), nullptr, &status)); LocalUResourceBundlePointer eraRuleRes(ures_getNextResource(rb.getAlias(), nullptr, &status));
if (U_FAILURE(status)) { if (U_FAILURE(status)) {
goto error; return nullptr;
} }
const char *eraIdxStr = ures_getKey(eraRuleRes.getAlias()); const char *eraIdxStr = ures_getKey(eraRuleRes.getAlias());
char *endp; char *endp;
int32_t eraIdx = (int32_t)strtol(eraIdxStr, &endp, 10); int32_t eraIdx = (int32_t)strtol(eraIdxStr, &endp, 10);
if ((size_t)(endp - eraIdxStr) != uprv_strlen(eraIdxStr)) { if ((size_t)(endp - eraIdxStr) != uprv_strlen(eraIdxStr)) {
status = U_INVALID_FORMAT_ERROR; status = U_INVALID_FORMAT_ERROR;
goto error; return nullptr;
} }
if (eraIdx < 0 || eraIdx >= numEras) { if (eraIdx < 0 || eraIdx >= numEras) {
status = U_INVALID_FORMAT_ERROR; status = U_INVALID_FORMAT_ERROR;
goto error; return nullptr;
} }
if (isSet(startDates[eraIdx])) { if (isSet(startDates[eraIdx])) {
// start date of the index was already set // start date of the index was already set
status = U_INVALID_FORMAT_ERROR; status = U_INVALID_FORMAT_ERROR;
goto error; return nullptr;
} }
UBool hasName = TRUE; UBool hasName = TRUE;
@ -159,17 +158,17 @@ EraRules* EraRules::createInstance(const char *calType, UBool includeTentativeEr
while (ures_hasNext(eraRuleRes.getAlias())) { while (ures_hasNext(eraRuleRes.getAlias())) {
LocalUResourceBundlePointer res(ures_getNextResource(eraRuleRes.getAlias(), nullptr, &status)); LocalUResourceBundlePointer res(ures_getNextResource(eraRuleRes.getAlias(), nullptr, &status));
if (U_FAILURE(status)) { if (U_FAILURE(status)) {
goto error; return nullptr;
} }
const char *key = ures_getKey(res.getAlias()); const char *key = ures_getKey(res.getAlias());
if (uprv_strcmp(key, "start") == 0) { if (uprv_strcmp(key, "start") == 0) {
const int32_t *fields = ures_getIntVector(res.getAlias(), &len, &status); const int32_t *fields = ures_getIntVector(res.getAlias(), &len, &status);
if (U_FAILURE(status)) { if (U_FAILURE(status)) {
goto error; return nullptr;
} }
if (len != 3 || !isValidRuleStartDate(fields[0], fields[1], fields[2])) { if (len != 3 || !isValidRuleStartDate(fields[0], fields[1], fields[2])) {
status = U_INVALID_FORMAT_ERROR; status = U_INVALID_FORMAT_ERROR;
goto error; return nullptr;
} }
startDates[eraIdx] = encodeDate(fields[0], fields[1], fields[2]); startDates[eraIdx] = encodeDate(fields[0], fields[1], fields[2]);
} else if (uprv_strcmp(key, "named") == 0) { } 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 // This implementation does not support end only rule for eras other than
// the first one. // the first one.
status = U_INVALID_FORMAT_ERROR; status = U_INVALID_FORMAT_ERROR;
goto error; return nullptr;
} }
U_ASSERT(eraIdx == 0); U_ASSERT(eraIdx == 0);
startDates[eraIdx] = MIN_ENCODED_START; startDates[eraIdx] = MIN_ENCODED_START;
} else { } else {
status = U_INVALID_FORMAT_ERROR; status = U_INVALID_FORMAT_ERROR;
goto error; return nullptr;
} }
} }
if (hasName) { if (hasName) {
if (eraIdx >= firstTentativeIdx) { if (eraIdx >= firstTentativeIdx) {
status = U_INVALID_FORMAT_ERROR; status = U_INVALID_FORMAT_ERROR;
goto error; return nullptr;
} }
} else { } else {
if (eraIdx < firstTentativeIdx) { if (eraIdx < firstTentativeIdx) {
@ -226,10 +225,6 @@ EraRules* EraRules::createInstance(const char *calType, UBool includeTentativeEr
status = U_MEMORY_ALLOCATION_ERROR; status = U_MEMORY_ALLOCATION_ERROR;
} }
return result; return result;
error:
uprv_free(startDates);
return nullptr;
} }
void EraRules::getStartDate(int32_t eraIdx, int32_t (&fields)[3], UErrorCode& status) const { void EraRules::getStartDate(int32_t eraIdx, int32_t (&fields)[3], UErrorCode& status) const {

View File

@ -12,6 +12,16 @@
U_NAMESPACE_BEGIN 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<int32_t>;
template class U_I18N_API LocalArray<int32_t>;
#endif
class U_I18N_API EraRules : public UMemory { class U_I18N_API EraRules : public UMemory {
public: public:
~EraRules(); ~EraRules();
@ -66,11 +76,11 @@ public:
} }
private: private:
EraRules(int32_t *startDates, int32_t numEra); EraRules(LocalArray<int32_t>& eraStartDates, int32_t numEra);
void initCurrentEra(); void initCurrentEra();
int32_t *startDates; LocalArray<int32_t> startDates;
int32_t numEras; int32_t numEras;
int32_t currentEra; int32_t currentEra;
}; };

View File

@ -59,11 +59,19 @@ static void U_CALLCONV initializeEras(UErrorCode &status) {
// By default, such tentative era is disabled. // By default, such tentative era is disabled.
// 1. Environment variable ICU_ENABLE_TENTATIVE_ERA=true or false // 1. Environment variable ICU_ENABLE_TENTATIVE_ERA=true or false
// 2. Windows registry (TBD)
UBool includeTentativeEra = FALSE; 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<int32_t>(uprv_strlen(TENTATIVE_ERA_VAR_NAME)));
WCHAR varValue[5] = {};
DWORD ret = GetEnvironmentVariableW(reinterpret_cast<WCHAR*>(varName), varValue, UPRV_LENGTHOF(varValue));
if ((ret == 4) && (_wcsicmp(varValue, L"true") == 0)) {
includeTentativeEra = TRUE;
}
#else
char *envVarVal = getenv(TENTATIVE_ERA_VAR_NAME); char *envVarVal = getenv(TENTATIVE_ERA_VAR_NAME);
if (envVarVal != NULL && uprv_stricmp(envVarVal, "true") == 0) { if (envVarVal != NULL && uprv_stricmp(envVarVal, "true") == 0) {
includeTentativeEra = TRUE; includeTentativeEra = TRUE;

View File

@ -130,7 +130,7 @@ class BasicTimeZone;
* *
* **Note:** for some non-Gregorian calendars, different * **Note:** for some non-Gregorian calendars, different
* fields may be necessary for complete disambiguation. For example, a full * 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. * month, day-of-month *and* day-of-week in some cases.
* *
* **Note:** There are certain possible ambiguities in * **Note:** There are certain possible ambiguities in
@ -886,7 +886,7 @@ public:
/** /**
* Sets the behavior for handling wall time repeating multiple times * Sets the behavior for handling wall time repeating multiple times
* at negative time zone offset transitions. For example, 1:30 AM on * 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 <code>UCAL_WALLTIME_FIRST</code> * 1:30 AM EDT, then 1:30 AM EST one hour later. When <code>UCAL_WALLTIME_FIRST</code>
* is used, the wall time 1:30AM in this example will be interpreted as 1:30 AM EDT * is used, the wall time 1:30AM in this example will be interpreted as 1:30 AM EDT
* (first occurrence). When <code>UCAL_WALLTIME_LAST</code> is used, it will be * (first occurrence). When <code>UCAL_WALLTIME_LAST</code> is used, it will be
@ -2152,7 +2152,7 @@ private:
TimeZone* fZone; TimeZone* fZone;
/** /**
* Option for rpeated wall time * Option for repeated wall time
* @see #setRepeatedWallTimeOption * @see #setRepeatedWallTimeOption
*/ */
UCalendarWallTimeOption fRepeatedWallTime; UCalendarWallTimeOption fRepeatedWallTime;
@ -2437,7 +2437,7 @@ private:
BasicTimeZone* getBasicTimeZone() const; 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 base The base time, inclusive
* @param transitionTime Receives the result time * @param transitionTime Receives the result time
* @param status The error status * @param status The error status