ICU-2487 refactor calendar data, support CLDR 1.1 format

X-SVN-Rev: 15363
This commit is contained in:
Steven R. Loomis 2004-05-18 02:06:28 +00:00
parent 39ea0e9fe4
commit 66753f4215
5 changed files with 311 additions and 130 deletions

View file

@ -203,70 +203,37 @@ class DefaultCalendarFactory : public ICUResourceBundleFactory {
// attempt keyword lookup
char keyword[128];
if(loc.getKeywordValue("calendar", keyword, sizeof(keyword)-1, status)) {
if(!loc.getKeywordValue("calendar", keyword, sizeof(keyword)-1, status)) {
// fetch default calendar id
const char *defaultCal = NULL;
char funcEquiv[256];
char keywordVal[ULOC_KEYWORD_AND_VALUES_CAPACITY];
ures_getFunctionalEquivalent(funcEquiv, sizeof(funcEquiv)-1,
NULL, "calendar", "calendar",
loc.getName(),
NULL, FALSE, &status);
uloc_getKeywordValue(funcEquiv, "calendar", keyword,
sizeof(keyword)-1, &status);
#ifdef U_DEBUG_CALSVC
fprintf(stderr, "DefaultCalendar factory %p: looking up %s, keyword: %s\n",
this, (const char*)loc.getName(), keyword);
fprintf(stderr, " getFunctionalEquivalent calendar=%s [%s]\n", keyword, u_errorName(status));
#endif
}
#ifdef U_DEBUG_CALSVC
else { fprintf(stderr, " explicit calendar=%s\n", keyword); }
#endif
if(U_FAILURE(status)) {
return NULL;
} else {
int i;
for(i=0;keyword[i];i++) {
keyword[i] = ::tolower(keyword[i]);
}
UnicodeString *ret = new UnicodeString("@calendar=","");
(*ret) += UnicodeString(keyword, "");
return ret;
} else {
#ifdef U_DEBUG_CALSVC
fprintf(stderr, "DefaultCalendar factory %p: looking up %s\n",
this, (const char*)loc.getName());
#endif
UErrorCode resStatus = U_ZERO_ERROR;
UResourceBundle *rb = ures_open(NULL, (const char*)loc.getName(), &resStatus);
#ifdef U_DEBUG_CALSVC
fprintf(stderr, "... ures_open -> %s\n", u_errorName(resStatus));
#endif
if(U_FAILURE(resStatus) ||
(resStatus == U_USING_DEFAULT_WARNING) || (resStatus==U_USING_FALLBACK_WARNING)) { //Don't want to handle fallback data.
ures_close(rb);
status = resStatus; // propagate err back to caller
#ifdef U_DEBUG_CALSVC
fprintf(stderr, "... exitting (NULL)\n");
#endif
return NULL;
}
UnicodeString myString = ures_getUnicodeStringByKey(rb, Calendar::kDefaultCalendar, &status);
myString = UnicodeString("@calendar=") + myString;
#ifdef U_DEBUG_CALSVC
int32_t len = 0;
UErrorCode debugStatus = U_ZERO_ERROR;
const UChar *defCal = ures_getStringByKey(rb, Calendar::kDefaultCalendar, &len, &debugStatus);
fprintf(stderr, "... get string(%d) -> %s\n", len, u_errorName(debugStatus));
#endif
ures_close(rb);
if(U_FAILURE(status)) {
return NULL;
}
#ifdef U_DEBUG_CALSVC
{
char defCalStr[200] = "@calendar=";
int32_t prefixLen = uprv_strlen(defCalStr);
if(len > (199-prefixLen)) {
len = (199-prefixLen);
}
u_UCharsToChars(defCal, defCalStr+prefixLen, len);
defCalStr[len+prefixLen]=0;
fprintf(stderr, "DefaultCalendarFactory: looked up %s, got DefaultCalendar= %s\n", (const char*)loc.getName(), defCalStr);
}
#endif
return myString.clone();
}
}
};
@ -416,7 +383,6 @@ static const int32_t kCalendarLimits[UCAL_FIELD_COUNT][4] = {
// Resource bundle tags read by this class
const char Calendar::kDateTimeElements[] = "DateTimeElements";
const char Calendar::kDefaultCalendar[] = "DefaultCalendar";
// Data flow in Calendar
// ---------------------
@ -2896,22 +2862,20 @@ Calendar::setWeekCountData(const Locale& desiredLocale, UErrorCode& status)
fFirstDayOfWeek = UCAL_SUNDAY;
fMinimalDaysInFirstWeek = 1;
UResourceBundle *resource = ures_open(NULL, desiredLocale.getName(), &status);
CalendarData calData(desiredLocale, "gregorian", status); // TODO: fixme
// If the resource data doesn't seem to be present at all, then use last-resort
// hard-coded data.
UResourceBundle *dateTimeElements = calData.getByKey(kDateTimeElements, status);
if (U_FAILURE(status))
{
status = U_USING_FALLBACK_WARNING;
ures_close(resource);
return;
}
//dateTimeElements = resource.getStringArray(kDateTimeElements, count, status);
UResourceBundle *dateTimeElements = ures_getByKey(resource, kDateTimeElements, NULL, &status); // TODO: should be per calendar?!
U_LOCALE_BASED(locBased, *this);
locBased.setLocaleIDs(ures_getLocaleByType(resource, ULOC_VALID_LOCALE, &status),
ures_getLocaleByType(resource, ULOC_ACTUAL_LOCALE, &status));
locBased.setLocaleIDs(ures_getLocaleByType(dateTimeElements, ULOC_VALID_LOCALE, &status),
ures_getLocaleByType(dateTimeElements, ULOC_ACTUAL_LOCALE, &status));
if (U_SUCCESS(status)) {
int32_t arrLen;
const int32_t *dateTimeElementsArr = ures_getIntVector(dateTimeElements, &arrLen, &status);
@ -2927,9 +2891,8 @@ Calendar::setWeekCountData(const Locale& desiredLocale, UErrorCode& status)
status = U_INVALID_FORMAT_ERROR;
}
}
ures_close(dateTimeElements);
ures_close(resource);
// do NOT close dateTimeElements
}
/**

View file

@ -30,6 +30,7 @@
#include "cmemory.h"
#include "cstring.h"
#include "locbased.h"
#include "gregoimp.h"
// *****************************************************************************
// class DateFormatSymbols
@ -117,13 +118,13 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateFormatSymbols)
/**
* These are the tags we expect to see in normal resource bundle files associated
* with a locale.
* with a locale and calendar
*/
const char gErasTag[]="Eras";
const char gMonthNamesTag[]="MonthNames";
const char gMonthAbbreviationsTag[]="MonthAbbreviations";
const char gDayNamesTag[]="DayNames";
const char gDayAbbreviationsTag[]="DayAbbreviations";
const char gErasTag[]="eras";
const char gMonthNamesTag[]="monthNames";
const char gDayNamesTag[]="dayNames";
const char gNamesWideTag[]="wide";
const char gNamesAbbrTag[]="abbreviated";
const char gAmPmMarkersTag[]="AmPmMarkers";
/**
@ -545,41 +546,6 @@ DateFormatSymbols::initField(UnicodeString **field, int32_t& length, const UChar
}
}
ResourceBundle
DateFormatSymbols::getData(ResourceBundle &rb, const char *tag, const char *type, UErrorCode& status )
{
if(type && *type && (uprv_strcmp(type, "gregorian") != 0)) {
char tmp[100];
char *fullTag = tmp;
int32_t len = uprv_strlen(tag) + 1 + uprv_strlen(type); // tag + _ + type (i.e. Eras_Japanese )
if(len >= (int32_t)sizeof(tmp)) {
fullTag = (char*)uprv_malloc(len+1);
}
uprv_strcpy(fullTag, tag);
uprv_strcat(fullTag, "_");
uprv_strcat(fullTag, type);
ResourceBundle resource(rb.get(fullTag, status));
if(fullTag != tmp) {
uprv_free(fullTag); // not stack allocated
}
// fallback if not found
if(status == U_MISSING_RESOURCE_ERROR) {
status = U_ZERO_ERROR;
resource = rb.get(tag, status);
}
return resource;
} else {
// Gregorian case
return rb.get(tag, status);
}
}
void
DateFormatSymbols::initializeData(const Locale& locale, const char *type, UErrorCode& status, UBool useLastResortData)
{
@ -610,7 +576,10 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
* We cast away const here, but that's okay; we won't delete any of
* these.
*/
ResourceBundle resource((char *)0, locale, status);
CalendarData calData(locale, type, status);
ResourceBundle nonCalendarData((char*)0, locale, status);
ResourceBundle data = calData.getBundleByKey(gErasTag, status); // load the first data item
if (U_FAILURE(status))
{
@ -646,18 +615,18 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
// if we make it to here, the resource data is cool, and we can get everything out
// of it that we need except for the time-zone and localized-pattern data, which
// are stored in a separate file
ResourceBundle data = getData(resource, gErasTag, type, status);
U_LOCALE_BASED(locBased, *this);
locBased.setLocaleIDs(data.getLocale(ULOC_VALID_LOCALE, status).getName(),
data.getLocale(ULOC_ACTUAL_LOCALE, status).getName());
initField(&fEras, fErasCount, data, status);
initField(&fMonths, fMonthsCount, getData(resource, gMonthNamesTag, type, status), status);
initField(&fShortMonths, fShortMonthsCount, getData(resource, gMonthAbbreviationsTag, type, status), status);
initField(&fAmPms, fAmPmsCount, getData(resource, gAmPmMarkersTag, type, status), status);
// fastCopyFrom() - see assignArray comments
fLocalPatternChars.fastCopyFrom(resource.getStringEx(gLocalPatternCharsTag, status));
initField(&fMonths, fMonthsCount, calData.getBundleByKey2(gMonthNamesTag, gNamesWideTag, status), status);
initField(&fShortMonths, fShortMonthsCount, calData.getBundleByKey2(gMonthNamesTag, gNamesAbbrTag, status), status);
initField(&fAmPms, fAmPmsCount, calData.getBundleByKey(gAmPmMarkersTag, status), status);
ResourceBundle zoneArray(resource.get(gZoneStringsTag, status));
// fastCopyFrom() - see assignArray comments
fLocalPatternChars.fastCopyFrom(nonCalendarData.getStringEx(gLocalPatternCharsTag, status));
ResourceBundle zoneArray(nonCalendarData.get(gZoneStringsTag, status));
fZoneStringsRowCount = zoneArray.getSize();
ResourceBundle zoneRow(zoneArray.get((int32_t)0, status));
/* TODO: Fix the case where the zoneStrings is not a perfect square array of information. */
@ -683,7 +652,7 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
}
// {sfb} fixed to handle 1-based weekdays
ResourceBundle weekdaysData(getData(resource, gDayNamesTag, type, status));
ResourceBundle weekdaysData(calData.getBundleByKey2(gDayNamesTag, gNamesWideTag, status));
fWeekdaysCount = weekdaysData.getSize();
fWeekdays = new UnicodeString[fWeekdaysCount+1];
/* test for NULL */
@ -698,7 +667,7 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
}
fWeekdaysCount++;
ResourceBundle lsweekdaysData(getData(resource, gDayAbbreviationsTag, type, status));
ResourceBundle lsweekdaysData(calData.getBundleByKey2(gDayNamesTag, gNamesAbbrTag, status));
fShortWeekdaysCount = lsweekdaysData.getSize();
fShortWeekdays = new UnicodeString[fShortWeekdaysCount+1];
/* test for NULL */

View file

@ -13,6 +13,8 @@
#if !UCONFIG_NO_FORMATTING
#include "unicode/ucal.h"
#include "uresimp.h"
#include "cstring.h"
int32_t Math::floorDivide(int32_t numerator, int32_t denominator) {
return (numerator >= 0) ?
@ -87,5 +89,155 @@ void Grego::dayToFields(double day, int32_t& year, int32_t& month,
doy++; // one-based doy
}
/* ---- CalendarData ------ */
#define U_CALENDAR_KEY "calendar"
#define U_GREGORIAN_KEY "gregorian"
#define U_FORMAT_KEY "format"
#define U_DEFAULT_KEY "default"
#define U_CALENDAR_DATA ((char*)0)
#if defined( U_DEBUG_CALDATA)
#include <stdio.h>
#endif
// CalendarData::CalendarData(const Locale& loc, UErrorCode& status)
// : fFillin(NULL), fBundle(NULL), fFallback(NULL) {
// initData(loc.getBaseName(), (char*) "???", status);
// }
CalendarData::CalendarData(const Locale& loc, const char *type, UErrorCode& status)
: fFillin(NULL), fOtherFillin(NULL), fBundle(NULL), fFallback(NULL) {
initData(loc.getBaseName(), type, status);
}
void CalendarData::initData(const char *locale, const char *type, UErrorCode& status) {
UResourceBundle *tmp = NULL;
fOtherFillin = ures_open(U_CALENDAR_DATA, locale, &status);
fFillin = ures_getByKey(fOtherFillin, U_CALENDAR_KEY, fFillin, &status);
if((type != NULL) &&
(*type != NULL) &&
(uprv_strcmp(type, U_GREGORIAN_KEY))) {
fBundle = ures_getByKeyWithFallback(fFillin, type, NULL, &status);
fFallback = ures_getByKeyWithFallback(fFillin, U_GREGORIAN_KEY, NULL, &status);
#if defined (U_DEBUG_CALDATA)
fprintf(stderr, "%p: CalendarData(%s, %s, %s) -> main(%p, %s)=%s, fallback(%p, %s)=%s\n",
this, locale, type, u_errorName(status), fBundle, type, fBundle?ures_getLocale(fBundle, &status):"",
fFallback, U_GREGORIAN_KEY, fFallback?ures_getLocale(fFallback, &status):"");
#endif
} else {
fBundle = ures_getByKeyWithFallback(fFillin, U_GREGORIAN_KEY, NULL, &status);
#if defined (U_DEBUG_CALDATA)
fprintf(stderr, "%p: CalendarData(%s, %s, %s) -> main(%p, %s)=%s, fallback = NULL\n",
this, locale, type, u_errorName(status), fBundle, U_GREGORIAN_KEY, fBundle?ures_getLocale(fBundle, &status):"" );
#endif
}
}
CalendarData::~CalendarData() {
ures_close(fFillin);
ures_close(fBundle);
ures_close(fFallback);
ures_close(fOtherFillin);
}
UResourceBundle*
CalendarData::getByKey(const char *key, UErrorCode& status) {
if(U_FAILURE(status)) {
return NULL;
}
if(fBundle) {
fFillin = ures_getByKeyWithFallback(fBundle, key, fFillin, &status);
#if defined (U_DEBUG_CALDATA)
fprintf(stderr, "%p: get %s -> %s - from MAIN %s\n",this, key, u_errorName(status), ures_getLocale(fFillin, &status));
#endif
}
if(fFallback && (status == U_MISSING_RESOURCE_ERROR)) {
status = U_ZERO_ERROR; // retry with fallback (gregorian)
fFillin = ures_getByKeyWithFallback(fFallback, key, fFillin, &status);
#if defined (U_DEBUG_CALDATA)
fprintf(stderr, "%p: get %s -> %s - from FALLBACK %s\n",this, key, u_errorName(status), ures_getLocale(fFillin, &status));
#endif
}
return fFillin;
}
ResourceBundle CalendarData::getBundleByKey(const char *key, UErrorCode &status) {
return ResourceBundle(getByKey(key,status), status);
}
UResourceBundle* CalendarData::getByKey2(const char *key, const char *subKey, UErrorCode& status) {
if(U_FAILURE(status)) {
return NULL;
}
if(fBundle) {
#if defined (U_DEBUG_CALDATA)
fprintf(stderr, "%p: //\n");
#endif
fFillin = ures_getByKeyWithFallback(fBundle, key, fFillin, &status);
fOtherFillin = ures_getByKeyWithFallback(fFillin, U_FORMAT_KEY, fOtherFillin, &status);
fFillin = ures_getByKeyWithFallback(fOtherFillin, subKey, fFillin, &status);
#if defined (U_DEBUG_CALDATA)
fprintf(stderr, "%p: get %s/format/%s -> %s - from MAIN %s\n", this, key, subKey, u_errorName(status), ures_getLocale(fFillin, &status));
#endif
}
if(fFallback && (status == U_MISSING_RESOURCE_ERROR)) {
status = U_ZERO_ERROR; // retry with fallback (gregorian)
fFillin = ures_getByKeyWithFallback(fFallback, key, fFillin, &status);
fOtherFillin = ures_getByKeyWithFallback(fFillin, U_FORMAT_KEY, fOtherFillin, &status);
fFillin = ures_getByKeyWithFallback(fOtherFillin, subKey, fFillin, &status);
#if defined (U_DEBUG_CALDATA)
fprintf(stderr, "%p: get %s/format/%s -> %s - from FALLBACK %s\n",this, key, subKey, u_errorName(status), ures_getLocale(fFillin,&status));
#endif
}
//// handling of 'default' keyword on failure: Commented out for 3.0.
// if((status == U_MISSING_RESOURCE_ERROR) &&
// uprv_strcmp(subKey,U_DEFAULT_KEY)) { // avoid recursion
// #if defined (U_DEBUG_CALDATA)
// fprintf(stderr, "%p: - attempting fallback -\n", this);
// fflush(stderr);
// #endif
// UErrorCode subStatus = U_ZERO_ERROR;
// int32_t len;
// char kwBuf[128] = "";
// const UChar *kw;
// /* fFillin = */ getByKey2(key, U_DEFAULT_KEY, subStatus);
// kw = ures_getString(fFillin, &len, &subStatus);
// if(len>126) { // too big
// len = 0;
// }
// if(U_SUCCESS(subStatus) && (len>0)) {
// u_UCharsToChars(kw, kwBuf, len+1);
// if(*kwBuf && uprv_strcmp(kwBuf,subKey)) {
// #if defined (U_DEBUG_CALDATA)
// fprintf(stderr, "%p: trying %s/format/default -> \"%s\"\n",this, key, kwBuf);
// #endif
// // now try again with the default
// status = U_ZERO_ERROR;
// /* fFillin = */ getByKey2(key, kwBuf, status);
// }
// #if defined (U_DEBUG_CALDATA)
// } else {
// fprintf(stderr, "%p: could not load %s/format/default - fail out (%s)\n",this, key, kwBuf, u_errorName(status));
// #endif
// }
// }
return fFillin;
}
ResourceBundle CalendarData::getBundleByKey2(const char *key, const char *subKey, UErrorCode& status) {
return ResourceBundle(getByKey2(key, subKey, status), status);
}
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CalendarData);
#endif
//eof

View file

@ -11,9 +11,11 @@
#ifndef GREGOIMP_H
#define GREGOIMP_H
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/ures.h"
#include "unicode/resbund.h"
U_NAMESPACE_BEGIN
/**
@ -220,6 +222,106 @@ inline int32_t Grego::gregorianShift(int32_t eyear) {
return gregShift;
}
/**
* This class provides convenient access to the data needed for a calendar.
* @internal ICU 3.0
*/
class U_I18N_API CalendarData : public UObject {
public:
/**
* Construct a CalendarData from the given locale.
* @param loc locale to use - the 'calendar' keyword will be used, respecting the
* 'default' value in the resource bundle.
* @param status error code
*/
//CalendarData(const Locale& loc, UErrorCode& status);
/**
* Construct a CalendarData from the given locale.
* @param loc locale to use. The 'calendar' keyword will be ignored.
* @param type calendar type. NULL indicates the gregorian calendar.
* No default lookup is done.
* @param status error code
*/
CalendarData(const Locale& loc, const char *type, UErrorCode& status);
/**
* Load data for calendar. Note, this object owns the resources, do NOT call ures_close()!
*
* @param key Resource key to data
* @param status Error Status
* @internal
*/
UResourceBundle* getByKey(const char *key, UErrorCode& status);
/**
* Load data for calendar. returns a ResourceBundle object
*
* @param key Resource key to data
* @param status Error Status
* @internal
*/
ResourceBundle getBundleByKey(const char *key, UErrorCode& status);
/**
* Load data for calendar. Note, this object owns the resources, do NOT call ures_close()!
* There is an implicit key of 'format'
* data is located in: "calendar/key/format/subKey"
* for example, calendar/dayNames/format/abbreviated
*
* @param key Resource key to data
* @param subKey Resource key to data
* @param status Error Status
* @internal
*/
UResourceBundle* getByKey2(const char *key, const char *subKey, UErrorCode& status);
/**
* Load data for calendar. Returns a ResourceBundle object
*
* @param key Resource key to data
* @param subKey Resource key to data
* @param status Error Status
* @internal
*/
ResourceBundle getBundleByKey2(const char *key, const char *subKey, UErrorCode& status);
~CalendarData();
/**
* Override Calendar Returns a unique class ID POLYMORPHICALLY. Pure virtual
* override. This method is to implement a simple version of RTTI, since not all C++
* compilers support genuine RTTI. Polymorphic operator==() and clone() methods call
* this method.
*
* @return The class ID for this object. All objects of a given class have the
* same class ID. Objects of other classes have different class IDs.
* @stable ICU 2.0
*/
virtual UClassID getDynamicClassID(void) const;
/**
* Return the class ID for this class. This is useful only for comparing to a return
* value from getDynamicClassID(). For example:
*
* Base* polymorphic_pointer = createPolymorphicObject();
* if (polymorphic_pointer->getDynamicClassID() ==
* Derived::getStaticClassID()) ...
*
* @return The class ID for all objects of this class.
* @stable ICU 2.0
*/
static UClassID getStaticClassID(void);
private:
void initData(const char *locale, const char *type, UErrorCode& status);
UResourceBundle *fFillin;
UResourceBundle *fOtherFillin;
UResourceBundle *fBundle;
UResourceBundle *fFallback;
CalendarData(); // Not implemented.
};
U_NAMESPACE_END

View file

@ -40,6 +40,7 @@
#include "unicode/uchar.h"
#include "unicode/ustring.h"
#include "uprops.h"
#include "gregoimp.h"
#include "cstring.h"
#include <float.h>
@ -270,19 +271,13 @@ void SimpleDateFormat::construct(EStyle timeStyle,
UErrorCode& status)
{
// called by several constructors to load pattern data from the resources
if (U_FAILURE(status)) return;
// load up the DateTimePatterns resource from the appropriate locale (throw
// an error if for some weird reason the resource is malformed)
ResourceBundle resources((char *)0, locale, status);
// We will need the calendar to know what type of symbols to load.
initializeCalendar(NULL, locale, status);
// use Date Format Symbols' helper function to do the actual load.
ResourceBundle dateTimePatterns = DateFormatSymbols::getData(resources, gDateTimePatternsTag, fCalendar?fCalendar->getType():NULL, status);
CalendarData calData(locale, fCalendar?fCalendar->getType():NULL, status);
ResourceBundle dateTimePatterns = calData.getBundleByKey(gDateTimePatternsTag, status);
if (U_FAILURE(status)) return;
if (dateTimePatterns.getSize() <= kDateTime)