1// © 2017 and later: Unicode, Inc. and others. 2// License & terms of use: http://www.unicode.org/copyright.html 3/* 4******************************************************************************* 5* 6* Copyright (C) 2009-2012, International Business Machines 7* Corporation and others. All Rights Reserved. 8* 9******************************************************************************* 10*/ 11#define CAL_FE_DEBUG 1 12 13#ifndef CAL_FE_DEBUG 14#define CAL_FE_DEBUG 0 15#endif 16 17#if CAL_FE_DEBUG 18#define debugfprintf(x) fflush(stderr),fflush(stdout),fprintf x,fflush(stderr),fflush(stdout) 19#else 20#define debugfprintf(x) 21#endif 22 23#include <icuglue/icuglue.h> 24#include "unicode/ucal.h" 25//#include <unicode/tblcoll.h> 26#include "unicode/calendar.h" 27#include <string.h> 28#include <stdio.h> 29#include "unicode/ustring.h" 30#include "unicode/gregocal.h" 31 32 33 34/** 35 * Macro to define the Calendar_glue_4_2 class 36 */ 37#ifdef GLUE_VER 38#error GLUE_VER is defined 39#endif 40 41#define GLUE_VER(x) class GLUE_SYM_V( Calendar, x ) : public Calendar { \ 42public: /* static create */ \ 43 UCalendar *_this; GLUE_SYM_V( Calendar, x ) ( const Locale&, UErrorCode& ); \ 44private: \ 45 virtual ~ GLUE_SYM_V ( Calendar, x) (); \ 46 public: \ 47 virtual void* getDynamicClassID() const; \ 48 static void* getStaticClassID() ; \ 49 /* overrides */ \ 50 virtual UBool haveDefaultCentury() const; \ 51 virtual UDate defaultCenturyStart() const ; \ 52 virtual int32_t handleGetExtendedYear() ; \ 53virtual const char * getType() const ; \ 54virtual UBool inDaylightTime(UErrorCode& status) const ; \ 55 virtual int32_t defaultCenturyStartYear() const ; \ 56 virtual int32_t handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth) const ; \ 57 virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const ; \ 58 virtual Calendar* clone(void) const; \ 59 public: static int32_t countAvailable(); \ 60public: static int32_t appendAvailable(UnicodeString* strs, int32_t i, int32_t count); \ 61 }; 62 63 64/** ==================================== The following code runs inside the 'target' version (i.e. old ICU) ========== **/ 65#if defined ( ICUGLUE_VER ) 66 67/* code for some version */ 68#include <icuglue/gluren.h> 69#include "oicu.h" 70 71#ifdef GLUE_VER 72GLUE_VER( ICUGLUE_VER ) 73#endif 74 75GLUE_SYM (Calendar ) :: GLUE_SYM(Calendar) ( const Locale& loc, UErrorCode& status ) : 76Calendar(status), _this(NULL) 77{ 78 79 _this = OICU_ucal_open(NULL, -1, /*locale*/NULL, UCAL_DEFAULT, &status); 80 81 // copy some things over 82 setMinimalDaysInFirstWeek(OICU_ucal_getAttribute(_this, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK)); 83 setFirstDayOfWeek((UCalendarDaysOfWeek)OICU_ucal_getAttribute(_this, UCAL_FIRST_DAY_OF_WEEK)); 84} 85 86GLUE_SYM ( Calendar ) :: ~ GLUE_SYM(Calendar) () { 87#if CAL_FE_DEBUG 88 fprintf(stderr, "VCF " ICUGLUE_VER_STR " ucal_close"); 89#endif 90 OICU_ucal_close(_this); 91} 92 93 94UBool GLUE_SYM ( Calendar ) :: haveDefaultCentury() const { 95 return false; 96} 97UDate GLUE_SYM ( Calendar ) :: defaultCenturyStart() const { 98 return 0L; 99} 100int32_t GLUE_SYM ( Calendar ) :: handleGetExtendedYear() { 101 return 0; 102} 103const char * GLUE_SYM ( Calendar ) :: getType() const { 104 return "dilbert"; 105} 106UBool GLUE_SYM ( Calendar ) :: inDaylightTime(UErrorCode& status) const { 107 return false; 108} 109int32_t GLUE_SYM ( Calendar ) :: defaultCenturyStartYear() const { 110 return 2012; 111} 112int32_t GLUE_SYM ( Calendar ) :: handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth) const { 113 return 0; 114} 115 116int32_t GLUE_SYM ( Calendar ) :: handleGetLimit(UCalendarDateFields field, ELimitType limitType) const { 117 return 1; 118} 119Calendar* GLUE_SYM ( Calendar ) :: clone(void) const { 120 return NULL; 121} 122 123 124// DateFormat * 125// GLUE_SYM ( DateFormat ) :: create(UDateFormatStyle timeStyle, 126// UDateFormatStyle dateStyle, 127// const char *locale, 128// const UChar *tzID, 129// int32_t tzIDLength, 130// const UChar *pattern, 131// int32_t patternLength, 132// UErrorCode *status, 133// const Locale &loc, const char */*ver*/) { 134// // TODO: save version 135// //char locBuf[200]; 136// //char kwvBuf[200]; 137// UDateFormat * uc = OICU_udat_open( timeStyle, dateStyle, locale, 138// tzID, 139// tzIDLength, 140// pattern, 141// patternLength, 142// status); 143// if(U_FAILURE(*status)) return NULL; // TODO: ERR? 144// DateFormat *c = new GLUE_SYM( DateFormat ) ( uc ); 145// #if CAL_FE_DEBUG 146// fprintf(stderr, "VCF " ICUGLUE_VER_STR " udat_open=%s ->> %p\n", loc.getName(), (void*)c); 147// #endif 148// return c; 149// } 150 151 152 int32_t GLUE_SYM ( Calendar ) :: countAvailable() { 153 int32_t count = OICU_udat_countAvailable(); 154 return count; 155 } 156 157 158int32_t GLUE_SYM ( Calendar ) :: appendAvailable(UnicodeString* strs, int32_t i, int32_t /*count*/) { 159 int avail = OICU_udat_countAvailable(); 160 UErrorCode status = U_ZERO_ERROR; 161 OICU_u_init(&status); 162#if CAL_FE_DEBUG 163 fprintf(stderr, "VCF " ICUGLUE_VER_STR " avail %d - init %s\n", avail, u_errorName(status)); 164#endif 165 for(int j=0;j<avail;j++) { 166 strs[i+j].append(OICU_udat_getAvailable(j)); 167 strs[i+j].append("@sp=icu"); 168 if(IS_OLD_VERSTR(ICUGLUE_VER_STR)) { 169 strs[i+j].append( ICUGLUE_VER_STR[OLD_VERSTR_MAJ] ); // X_y 170 strs[i+j].append( ICUGLUE_VER_STR[OLD_VERSTR_MIN] ); // x_Y 171 } else { 172 strs[i+j].append( ICUGLUE_VER_STR[NEW_VERSTR_MAJ] ); // Xy_ 173 strs[i+j].append( ICUGLUE_VER_STR[NEW_VERSTR_MIN] ); // xY_ 174 } 175#if CAL_FE_DEBUG 176 { 177 char foo[999]; 178 const UChar *ss = strs[i+j].getTerminatedBuffer(); 179 u_austrcpy(foo, ss); 180 fprintf(stderr, "VCF " ICUGLUE_VER_STR " appending [%d+%d=%d] <<%s>>\n", i, j, i+j, foo); 181 } 182#endif 183 } 184 return OICU_ucol_countAvailable(); 185 } 186 187UOBJECT_DEFINE_RTTI_IMPLEMENTATION( GLUE_SYM( Calendar ) ) 188 189 190 191 192#else 193/** ==================================== The following code runs inside the 'provider' version (i.e. current ICU) ========== **/ 194 195// #if (U_ICU_VERSION_MAJOR_NUM < 49) 196// #define CAL_PROVIDER_UNSUPPORTED 197// #endif 198 199#ifndef CAL_PROVIDER_UNSUPPORTED 200// define Collator_XX 201#include "icuglue/glver.h" 202 203#include "servloc.h" 204 205// generate list of versions 206static 207#include <icuglue/fe_verlist.h> 208 209class VersionCalendarFactory : public LocaleKeyFactory { 210public: 211 VersionCalendarFactory(); 212 virtual UObject* handleCreate(const Locale &loc, int32_t kind, const ICUService* service, UErrorCode& status) const; 213 // virtual Calendar *createFormat(UCalendarStyle timeStyle, 214 // UCalendarStyle dateStyle, 215 // const char *locale, 216 // const UChar *tzID, 217 // int32_t tzIDLength, 218 // const UChar *pattern, 219 // int32_t patternLength, 220 // UErrorCode *status); 221 virtual void* getDynamicClassID() const; 222 static void* getStaticClassID() ; 223 virtual const Hashtable* getSupportedIDs(UErrorCode& status) const; 224private: 225 const UnicodeString *getSupportedIDs(int32_t &count, UErrorCode &status) const; 226 227public: 228virtual UObject* 229 create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const ; 230 231}; 232 233UOBJECT_DEFINE_RTTI_IMPLEMENTATION( VersionCalendarFactory ) 234 235UObject* 236VersionCalendarFactory::create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const { 237 // UnicodeString id; 238 // key.currentID(id); 239 // Locale l(id); 240 Locale l; 241 const LocaleKey& lkey = (LocaleKey&)key; 242 lkey.currentLocale(l); 243 debugfprintf((stderr, "VCalF::create() .. %s err=%s\n", (const char*)l.getName(), u_errorName(status))); 244 245 char kw[100]; 246 int32_t kwlen = l.getKeywordValue("sp", kw, 100, status); 247 248 UObject *f; 249 if(kwlen>0) { 250 debugfprintf((stderr, "Trying for kw=%s\n", kw)); 251 f = handleCreate(l, -1, service, status); 252 } else { 253 f = LocaleKeyFactory::create(key,service,status); 254 } 255 256 257 258 debugfprintf((stderr, "VCalF::create() .. = %p err=%s\n", (void*)f, u_errorName(status))); 259 return f; 260} 261 262VersionCalendarFactory::VersionCalendarFactory() :LocaleKeyFactory(LocaleKeyFactory::VISIBLE){ 263#if CAL_FE_DEBUG 264 printf("VCalF: hi! pid=%d, this=%p\n", getpid(), (void*)this); 265#endif 266} 267UObject* VersionCalendarFactory::handleCreate(const Locale &loc, int32_t kind, const ICUService* service, UErrorCode& status) const { 268 //Locale loc(locale); 269 // pull off provider # 270 char provider[200]; 271#if CAL_FE_DEBUG 272 fprintf(stderr, "VCalF:CC %s\n", loc.getName()); 273#endif 274 int32_t len = loc.getKeywordValue("sp", provider, 200, status); 275 if(U_FAILURE(status)||len==0) return NULL; 276#if CAL_FE_DEBUG 277 fprintf(stderr, "VCalF:KWV> %s/%d\n", u_errorName(status), len); 278#endif 279 provider[len]=0; 280#if CAL_FE_DEBUG 281 fprintf(stderr, "VCalF:KWV %s\n", provider); 282#endif 283 if(strncmp(provider,"icu",3)) return NULL; 284 const char *icuver=provider+3; 285#if CAL_FE_DEBUG 286 fprintf(stderr, "VCalF:ICUV %s\n", icuver); 287#endif 288 289#if defined(GLUE_VER) 290#undef GLUE_VER 291#endif 292#define GLUE_VER(x) debugfprintf((stderr,"%c/%c|%c/%c\n", icuver[0],(#x)[0],icuver[1],(#x)[2])); if(CMP_VERSTR(icuver, (#x))) { Calendar *c = new glue ## Calendar ## x (loc, status); debugfprintf((stderr, "VCalF::CC %s -> %p\n", loc.getName(), c)); return c; } 293#include "icuglue/glver.h" 294#if CAL_FE_DEBUG 295 fprintf(stderr, "VCalF:CC %s failed\n", loc.getName()); 296#endif 297 298 return NULL; 299} 300 301 302static const UnicodeString *gLocalesDate = NULL; 303static int32_t gLocCountDate = 0; 304 305const Hashtable *VersionCalendarFactory::getSupportedIDs (UErrorCode& status) const { 306 // from coll.cpp 307 Hashtable *_ids = NULL; 308 if (U_SUCCESS(status)) { 309 int32_t count = 0; 310 _ids = new Hashtable(status); 311 if (_ids) { 312 const UnicodeString * idlist = /* _delegate -> */ getSupportedIDs(count, status); 313 for (int i = 0; i < count; ++i) { 314 _ids->put(idlist[i], (void*)this, status); 315 if (U_FAILURE(status)) { 316 delete _ids; 317 _ids = NULL; 318 return; 319 } 320 } 321 } else { 322 status = U_MEMORY_ALLOCATION_ERROR; 323 } 324 debugfprintf((stderr,"VCalF: hash=%p, count=%d, err=%s\n", (void*)_ids, count, u_errorName(status))); 325 } 326 return _ids; 327} 328 329const UnicodeString 330*VersionCalendarFactory::getSupportedIDs(int32_t &count, UErrorCode &/*status*/) const { 331 if(gLocalesDate==NULL) { 332 count = 0; 333 334 335 /* gather counts */ 336 337#if defined(GLUE_VER) 338#undef GLUE_VER 339#endif 340#define GLUE_VER(x) count += glue ## Calendar ## x :: countAvailable(); 341#include "icuglue/glver.h" 342 343#if CAL_FE_DEBUG 344 printf("VCalF: count=%d\n", count); 345#endif 346 UnicodeString *strs = new UnicodeString[count]; 347 int32_t i = 0; 348 349#if defined(GLUE_VER) 350#undef GLUE_VER 351#endif 352#define GLUE_VER(x) i += glue ## Calendar ## x :: appendAvailable(strs, i, count); 353#include "icuglue/glver.h" 354 355#if CAL_FE_DEBUG 356 printf("VCalF: appended count=%d\n", count); 357#endif 358 359 gLocCountDate = count; 360 gLocalesDate = strs; 361 } 362 count = gLocCountDate; 363 return gLocalesDate; 364} 365 366 367/* Plugin Code */ 368 369#include <stdio.h> 370#include <unicode/uversion.h> 371 372static URegistryKey rkcal = NULL; 373 374void cal_provider_register(UErrorCode &status) { 375 debugfprintf((stderr, "about to register VCalF\n")); 376 rkcal = Calendar::registerFactory(new VersionCalendarFactory(), status); 377 debugfprintf((stderr, ".. registered VCalF, key=%p\n", (void*)rkcal)); 378} 379 380void cal_provider_unregister(UErrorCode &status) { 381 Calendar::unregister(rkcal, status); 382} 383 384#else 385 386/* no op- this ICU doesn't support date providers */ 387 388void cal_provider_register(UErrorCode &) { 389 // not supported 390} 391 392void cal_provider_unregister(UErrorCode &) { 393 // not supported 394} 395 396#endif 397 398/* Plugin- only ICU 4.4+ */ 399#if (U_ICU_VERSION_MAJOR_NUM > 4) || ((U_ICU_VERSION_MAJOR_NUM==4)&&(U_ICU_VERSION_MINOR_NUM>3)) 400#include "unicode/icuplug.h" 401 402U_CAPI UPlugTokenReturn U_EXPORT2 cal_provider_plugin (UPlugData *data, UPlugReason reason, UErrorCode *status); 403 404U_CAPI UPlugTokenReturn U_EXPORT2 cal_provider_plugin (UPlugData *data, UPlugReason reason, UErrorCode *status) 405{ 406 switch(reason) { 407 case UPLUG_REASON_QUERY: 408 uplug_setPlugName(data, "Calendar Provider Plugin"); 409 uplug_setPlugLevel(data, UPLUG_LEVEL_HIGH); 410 break; 411 case UPLUG_REASON_LOAD: 412 cal_provider_register(*status); 413 break; 414 case UPLUG_REASON_UNLOAD: 415 cal_provider_unregister(*status); 416 break; 417 default: 418 break; /* not handled */ 419 } 420 return UPLUG_TOKEN; 421} 422#else 423 424/* 425 Note: this ICU version must explicitly call 'cal_provider_plugin' 426*/ 427 428#endif /* plugin */ 429 430#endif /* provider side (vs target) */ 431