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