d503e088创建于 2025年12月11日历史提交
// © 2017 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
*
*   Copyright (C) 2009-2012, International Business Machines
*   Corporation and others.  All Rights Reserved.
*
*******************************************************************************
*/

#ifndef DATE_FE_DEBUG
#define DATE_FE_DEBUG 0
#endif

#include <icuglue/icuglue.h>
#include "unicode/udat.h"
//#include <unicode/tblcoll.h>
#include "unicode/datefmt.h"
#include "unicode/smpdtfmt.h"
#include <string.h>
#include <stdio.h>
#include "unicode/ustring.h"
#include "unicode/gregocal.h"



/**
 * Macro to define the Collator_glue_4_2 class 
 */
#ifdef GLUE_VER
#error GLUE_VER is defined
#endif

#define GLUE_VER(x) class GLUE_SYM_V( DateFormat, x ) : public DateFormat {  \
  public:  static DateFormat *create(UDateFormatStyle  timeStyle, \
                                                    UDateFormatStyle  dateStyle, \
                                                    const char        *locale, \
                                                    const char16_t    *tzID, \
                                                    int32_t           tzIDLength, \
                                                    const char16_t    *pattern,  \
                                                    int32_t           patternLength,  \
                                                      UErrorCode        *status, const Locale &loc, const char *ver); \
  private: UDateFormat *_this; GLUE_SYM_V( DateFormat, x ) ( UDateFormat* tn ); \
    virtual ~ GLUE_SYM_V ( DateFormat, x) ();                             \
  public:                                                               \
    virtual void* getDynamicClassID() const;                            \
    static void* getStaticClassID() ;                                   \
    virtual UnicodeString& format(  Calendar& cal, UnicodeString& appendTo, FieldPosition& pos) const; \
    virtual void parse( const UnicodeString& text, Calendar& cal, ParsePosition& pos) const; \
    virtual Format* clone() const; \
  public: static int32_t countAvailable();                              \
public: static int32_t appendAvailable(UnicodeString* strs, int32_t i, int32_t count); \
  }; \



/** ==================================== The following code runs inside the 'target' version (i.e. old ICU) ========== **/
#if defined ( ICUGLUE_VER )



/* code for some version */
#include <icuglue/gluren.h>
#include "oicu.h"

#ifdef GLUE_VER
GLUE_VER( ICUGLUE_VER )
#endif

GLUE_SYM (DateFormat ) :: GLUE_SYM(DateFormat) ( UDateFormat* tn) :
 _this(tn)
{ 

  UErrorCode status = U_ZERO_ERROR;
  adoptCalendar(new GregorianCalendar(status));
}

GLUE_SYM ( DateFormat ) :: ~ GLUE_SYM(DateFormat) () {
#if DATE_FE_DEBUG
    fprintf(stderr, "VCF " ICUGLUE_VER_STR " udat_close");
#endif
    OICU_udat_close(_this);
}

DateFormat *
GLUE_SYM ( DateFormat ) :: create(UDateFormatStyle  timeStyle,
                                                    UDateFormatStyle  dateStyle,
                                                    const char        *locale,
                                                    const char16_t    *tzID,
                                                    int32_t           tzIDLength,
                                                    const char16_t    *pattern,
                                                    int32_t           patternLength,
                                                    UErrorCode        *status,
                                  const Locale &loc, const char */*ver*/) {
  // TODO: save version
  //char locBuf[200];
  //char kwvBuf[200];
  UDateFormat * uc =  OICU_udat_open( timeStyle, dateStyle, locale,
                                      tzID,
                                      tzIDLength,
                                      pattern,
                                      patternLength,
                                      status);
    if(U_FAILURE(*status)) return nullptr; // TODO: ERR?
    DateFormat *c =  new GLUE_SYM( DateFormat ) ( uc );
#if DATE_FE_DEBUG
    fprintf(stderr, "VCF " ICUGLUE_VER_STR " udat_open=%s ->> %p\n", loc.getName(), (void*)c);
#endif
    return c;
}

UnicodeString& GLUE_SYM (DateFormat ) :: format(  Calendar& cal, UnicodeString& appendTo, FieldPosition& pos) const
{
#if DATE_FE_DEBUG
  fprintf(stderr, "VCF " ICUGLUE_VER_STR " - formatting. \n");
#endif
  int32_t len = appendTo.length();

  char16_t junk[200];
  UErrorCode status = U_ZERO_ERROR;

  UFieldPosition pos2;

  int32_t nlen = OICU_udat_format(_this,
                                  cal.getTime(status),
                                  junk,
                                  200,
                                  &pos2,
                                  &status);

  // todo: use pos2
  pos.setBeginIndex(len);
  pos.setEndIndex(len += nlen);
  appendTo.append(junk, nlen);

  return appendTo;
}

void  GLUE_SYM (DateFormat ) :: parse( const UnicodeString& text, Calendar& cal, ParsePosition& pos) const
{
  return;
}

Format*  GLUE_SYM (DateFormat ) :: clone() const
{
  return nullptr;
}



 int32_t GLUE_SYM ( DateFormat ) :: countAvailable() {
    int32_t count =  OICU_udat_countAvailable();
    return count;
 }
 
 
int32_t GLUE_SYM ( DateFormat ) :: appendAvailable(UnicodeString* strs, int32_t i, int32_t /*count*/) {
   int avail = OICU_udat_countAvailable();
   UErrorCode status = U_ZERO_ERROR;
   OICU_u_init(&status);
#if DATE_FE_DEBUG
   fprintf(stderr,  "VCF " ICUGLUE_VER_STR " avail %d - init %s\n", avail, u_errorName(status));
#endif   
    for(int j=0;j<avail;j++) {
         strs[i+j].append(OICU_udat_getAvailable(j));
         strs[i+j].append("@sp=icu");
         strs[i+j].append( ICUGLUE_VER_STR[0] );  // X_y
         strs[i+j].append( ICUGLUE_VER_STR[2] );  // x_Y
#if DATE_FE_DEBUG
         { 
            char foo[999];
            const char16_t *ss = strs[i+j].getTerminatedBuffer();
            u_austrcpy(foo, ss);
            //            fprintf(stderr,  "VCF " ICUGLUE_VER_STR " appending [%d+%d=%d] <<%s>>\n", i, j, i+j, foo);
        }
#endif
    }
    return OICU_ucol_countAvailable();
 }

UOBJECT_DEFINE_RTTI_IMPLEMENTATION( GLUE_SYM( DateFormat ) )




#else
/** ==================================== The following code runs inside the 'provider' version (i.e. current ICU) ========== **/

#if (U_ICU_VERSION_MAJOR_NUM < 49)
#define DATE_PROVIDER_UNSUPPORTED
#endif

#ifndef DATE_PROVIDER_UNSUPPORTED
// define Collator_XX
#include "icuglue/glver.h"

// generate list of versions
static
#include <icuglue/fe_verlist.h>

class VersionDateFormatFactory : public UObject  {
public:
  virtual DateFormat *createFormat(UDateFormatStyle  timeStyle,
                                   UDateFormatStyle  dateStyle,
                                   const char        *locale,
                                   const char16_t    *tzID,
                                   int32_t           tzIDLength,
                                   const char16_t    *pattern,
                                   int32_t           patternLength,
                                   UErrorCode        *status);
  virtual const UnicodeString *getSupportedIDs(int32_t &count, UErrorCode &status);
  virtual void* getDynamicClassID() const; 
  static void* getStaticClassID() ; 
};

UOBJECT_DEFINE_RTTI_IMPLEMENTATION( VersionDateFormatFactory )

DateFormat *VersionDateFormatFactory::createFormat(UDateFormatStyle  timeStyle,
                                                    UDateFormatStyle  dateStyle,
                                                    const char        *locale,
                                                    const char16_t    *tzID,
                                                    int32_t           tzIDLength,
                                                    const char16_t    *pattern,
                                                    int32_t           patternLength,
                                                       UErrorCode        *status) {
    Locale loc(locale);
    // pull off provider #
    char provider[200];
#if DATE_FE_DEBUG
    fprintf(stderr,  "VCF:CC %s\n", loc.getName());
#endif
    int32_t len = loc.getKeywordValue("sp", provider, 200, *status);
    if(U_FAILURE(*status)||len==0) return nullptr;
#if DATE_FE_DEBUG
    fprintf(stderr,  "VCF:KWV> %s/%d\n", u_errorName(*status), len);
#endif
    provider[len]=0;
#if DATE_FE_DEBUG
    fprintf(stderr,  "VCF:KWV %s\n", provider);
#endif
    if(strncmp(provider,"icu",3)) return nullptr;
    const char *icuver=provider+3;
#if DATE_FE_DEBUG
    fprintf(stderr,  "VCF:ICUV %s\n", icuver);
#endif
    
#if defined(GLUE_VER)
#undef GLUE_VER
#endif
#define GLUE_VER(x) /*printf("%c/%c|%c/%c\n", icuver[0],(#x)[0],icuver[1],(#x)[2]);*/  if(icuver[0]== (#x)[0] && icuver[1]==(#x)[2]) { DateFormat *c = glue ## DateFormat ## x :: create(timeStyle,dateStyle,locale,tzID,tzIDLength,pattern,patternLength,status,loc,icuver); /*fprintf(stderr, "VCF::CC %s -> %p\n", loc.getName(), c);*/ return c; }
#include "icuglue/glver.h"
#if DATE_FE_DEBUG
    fprintf(stderr,  "VCF:CC %s failed\n", loc.getName());
#endif

    return nullptr;
}


static const UnicodeString *gLocalesDate = nullptr;
static  int32_t gLocCountDate = 0; 


const UnicodeString
*VersionDateFormatFactory::getSupportedIDs(int32_t &count, UErrorCode &/*status*/) {
  if(gLocalesDate==nullptr) {
    count = 0;
    
    
    /* gather counts */

#if defined(GLUE_VER)
#undef GLUE_VER
#endif
#define GLUE_VER(x) count += glue ## DateFormat ## x :: countAvailable();
#include "icuglue/glver.h"

#if DATE_FE_DEBUG
    printf("VCF: count=%d\n", count);
#endif
    UnicodeString *strs = new  UnicodeString[count];
    int32_t i = 0;

#if defined(GLUE_VER)
#undef GLUE_VER
#endif
#define GLUE_VER(x) i += glue ## DateFormat ## x :: appendAvailable(strs, i, count);
#include "icuglue/glver.h"

#if DATE_FE_DEBUG
    printf("VCF: appended count=%d\n", count);
#endif

    gLocCountDate = count;
    gLocalesDate = strs;
  }
  count = gLocCountDate;
  return gLocalesDate;
}


/* Plugin Code */

#include <stdio.h>
#include <unicode/uversion.h>

//static URegistryKey rkdate = nullptr;

static VersionDateFormatFactory vdf;

extern "C" UDateFormat *versionDateFormatOpener(UDateFormatStyle  timeStyle,
                                                    UDateFormatStyle  dateStyle,
                                                    const char        *locale,
                                                    const char16_t    *tzID,
                                                    int32_t           tzIDLength,
                                                    const char16_t    *pattern,
                                                    int32_t           patternLength,
                                                       UErrorCode        *status) {
  DateFormat *df = vdf.createFormat(timeStyle,dateStyle,locale,tzID,tzIDLength,pattern,patternLength,status);
  // printf("Hey! I got: %s -> %p\n", locale, df);
  return (UDateFormat*)df;
}

void date_provider_register(UErrorCode &status) {
  udat_registerOpener(versionDateFormatOpener, &status);
  //   rkdate = DateFormat::registerFactory(new VersionDateFormatFactory(), status);
}

void date_provider_unregister(UErrorCode &status) {
  udat_unregisterOpener(versionDateFormatOpener, &status);
}

#else

/* no op- this ICU doesn't support date providers */

void date_provider_register(UErrorCode &) {
  // not supported
}

void date_provider_unregister(UErrorCode &) {
  // not supported
}

#endif

/* Plugin- only ICU 4.4+ */
#if (U_ICU_VERSION_MAJOR_NUM > 4) || ((U_ICU_VERSION_MAJOR_NUM==4)&&(U_ICU_VERSION_MINOR_NUM>3))
#include "unicode/icuplug.h"

U_CAPI UPlugTokenReturn U_EXPORT2 date_provider_plugin (UPlugData *data, UPlugReason reason, UErrorCode *status);

U_CAPI UPlugTokenReturn U_EXPORT2 date_provider_plugin (UPlugData *data, UPlugReason reason, UErrorCode *status)
{
  switch(reason) {
  case UPLUG_REASON_QUERY:
    uplug_setPlugName(data, "Date Provider Plugin");
    uplug_setPlugLevel(data, UPLUG_LEVEL_HIGH);
    break;
  case UPLUG_REASON_LOAD:
    date_provider_register(*status);
    break;
  case UPLUG_REASON_UNLOAD:
    date_provider_unregister(*status);
    break;
  default:
    break; /* not handled */
  }
  return UPLUG_TOKEN;
}
#else

/* 
   Note: this ICU version must explicitly call 'date_provider_plugin'
*/

#endif /* plugin */

#endif /* provider side (vs target) */