[sword-svn] r214 - in trunk: . source source/common source/common/unicode source/config source/extra/uconv source/i18n source/i18n/unicode source/layout source/samples/layout source/tools/ctestfw source/tools/ctestfw/unicode source/tools/pkgdata source/tools/toolutil
chrislit at crosswire.org
chrislit at crosswire.org
Thu Jul 2 12:32:01 MST 2009
Author: chrislit
Date: 2009-07-02 12:32:00 -0700 (Thu, 02 Jul 2009)
New Revision: 214
Removed:
trunk/source/common/unicode/uspoof.h
trunk/source/layout/HindiFeatureTags.h
Modified:
trunk/readme.html
trunk/source/common/dtintrv.cpp
trunk/source/common/mutex.cpp
trunk/source/common/uloc.c
trunk/source/common/unicode/dtintrv.h
trunk/source/common/unicode/uversion.h
trunk/source/config/gmakever.mk
trunk/source/config/make2sh.sed
trunk/source/config/pkgdataMakefile.in
trunk/source/configure.mk
trunk/source/extra/uconv/pkgdataMakefile.in
trunk/source/extra/uconv/uconv.vcproj
trunk/source/i18n/currpinf.cpp
trunk/source/i18n/dtitv_impl.h
trunk/source/i18n/dtitvfmt.cpp
trunk/source/i18n/dtitvinf.cpp
trunk/source/i18n/dtptngen.cpp
trunk/source/i18n/tmunit.cpp
trunk/source/i18n/tmutamt.cpp
trunk/source/i18n/tmutfmt.cpp
trunk/source/i18n/unicode/currpinf.h
trunk/source/i18n/unicode/dtitvfmt.h
trunk/source/i18n/unicode/dtitvinf.h
trunk/source/i18n/unicode/dtptngen.h
trunk/source/i18n/unicode/smpdtfmt.h
trunk/source/i18n/unicode/tmunit.h
trunk/source/i18n/unicode/tmutamt.h
trunk/source/i18n/unicode/tmutfmt.h
trunk/source/i18n/uspoof_impl.cpp
trunk/source/samples/layout/cgnomelayout.c
trunk/source/tools/ctestfw/ctest.c
trunk/source/tools/ctestfw/tstdtmod.cpp
trunk/source/tools/ctestfw/unicode/ctest.h
trunk/source/tools/pkgdata/pkgdata.cpp
trunk/source/tools/toolutil/pkg_genc.c
trunk/source/tools/toolutil/pkg_genc.h
trunk/source/tools/toolutil/pkg_gencmn.c
trunk/source/tools/toolutil/pkg_gencmn.h
trunk/source/tools/toolutil/pkg_icu.cpp
trunk/source/tools/toolutil/pkg_icu.h
trunk/source/tools/toolutil/toolutil.c
Log:
ICU 4.2.1 update, sixth pass
Modified: trunk/readme.html
===================================================================
--- trunk/readme.html 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/readme.html 2009-07-02 19:32:00 UTC (rev 214)
@@ -17,9 +17,9 @@
<body class="readme">
<h1>International Components for Unicode<br />
- <abbr title="International Components for Unicode">ICU</abbr> 4.2.0.1 ReadMe</h1>
+ <abbr title="International Components for Unicode">ICU</abbr> 4.2.1 ReadMe</h1>
- <p>Version: 2009 May 20th<br />
+ <p>Version: 2009 July 1st<br />
Copyright © 1997-2009 International Business Machines Corporation and
others. All Rights Reserved.</p>
<!-- Remember that there is a copyright at the end too -->
@@ -200,9 +200,45 @@
<h2><a name="News" href="#News" id="News">What is new in this release?</a></h2>
- <p>ICU for C/C++ version 4.2.0.1 is a an update release of 4.2, containing selected platform and build related bug fixes. It does
- not introduce new API or functionality. These changes will be rolled into the next release of ICU.
- The overall ticket used for this release is <a href="http://bugs.icu-project.org/trac/ticket/6953">#6953</a>.
+ <p>ICU for C/C++ version 4.2.1 is a maintenance release of 4.2, containing fixes and updates in both code and data. It does
+ not introduce new API or functionality relative to 4.2. These changes will be rolled into the next release of ICU.
+ The overall ticket used for the 4.2.1 release is <a href="http://bugs.icu-project.org/trac/ticket/7018">#7018</a>.
+ Here is a list of the bug fixes included in 4.2.1, and the revisions used 4.2.1:
+ </p>
+ <ul>
+ <li>
+ <a href="http://bugs.icu-project.org/trac/ticket/6905">#6905</a>
+ <a href="http://bugs.icu-project.org/trac/changeset/26084">r26084</a> —
+ Make sure cintltst and intltest pass w/o data
+ </li>
+ <li>
+ <a href="http://bugs.icu-project.org/trac/ticket/6919">#6919</a>
+ <a href="http://bugs.icu-project.org/trac/changeset/26063">r26063</a> —
+ icu-config generation errors
+ </li>
+ <li>
+ <a href="http://bugs.icu-project.org/trac/ticket/6979">#6979</a>
+ <a href="http://bugs.icu-project.org/trac/changeset/26138">r26138</a> —
+ Integrate CLDR 1.7.1
+ </li>
+ <li>
+ <a href="http://bugs.icu-project.org/trac/ticket/6980">#6980</a>
+ <a href="http://bugs.icu-project.org/trac/changeset/26005">r26005</a> —
+ SimpleDateFormat serious compilation warnings
+ </li>
+ <li>
+ <a href="http://bugs.icu-project.org/trac/ticket/6908">#6908</a>
+ <a href="http://bugs.icu-project.org/trac/changeset/25978">r25978</a> —
+ Numbering Systems - Malayalam msising digit 5
+ </li>
+ <li>
+ <a href="http://bugs.icu-project.org/trac/ticket/6990">#6990</a>
+ <a href="http://bugs.icu-project.org/trac/changeset/26002">r26164</a> —
+ Update time zone data to version 2009j
+ </li>
+ </ul>
+ <p>
+ The overall ticket used for the 4.2.0.1 release was <a href="http://bugs.icu-project.org/trac/ticket/6953">#6953</a>.
Here is a list of the bug fixes included in 4.2.0.1, and the revisions used to patch 4.2.0.1:
</p>
<ul>
Modified: trunk/source/common/dtintrv.cpp
===================================================================
--- trunk/source/common/dtintrv.cpp 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/common/dtintrv.cpp 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,61 +1,61 @@
-/*******************************************************************************
-* Copyright (C) 2008, International Business Machines Corporation and
-* others. All Rights Reserved.
-*******************************************************************************
-*
-* File DTINTRV.CPP
-*
-*******************************************************************************
-*/
-
-
-
-#include "unicode/dtintrv.h"
-
-
-U_NAMESPACE_BEGIN
-
-UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateInterval)
-
-//DateInterval::DateInterval(){}
-
-
-DateInterval::DateInterval(UDate from, UDate to)
-: fromDate(from),
- toDate(to)
-{}
-
-
-DateInterval::~DateInterval(){}
-
-
-DateInterval::DateInterval(const DateInterval& other)
-: UObject(other) {
- *this = other;
-}
-
-
-DateInterval&
-DateInterval::operator=(const DateInterval& other) {
- if ( this != &other ) {
- fromDate = other.fromDate;
- toDate = other.toDate;
- }
- return *this;
-}
-
-
-DateInterval*
-DateInterval::clone() const {
- return new DateInterval(*this);
-}
-
-
-UBool
-DateInterval::operator==(const DateInterval& other) const {
- return ( fromDate == other.fromDate && toDate == other.toDate );
-}
-
-
-U_NAMESPACE_END
-
+/*******************************************************************************
+* Copyright (C) 2008, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File DTINTRV.CPP
+*
+*******************************************************************************
+*/
+
+
+
+#include "unicode/dtintrv.h"
+
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateInterval)
+
+//DateInterval::DateInterval(){}
+
+
+DateInterval::DateInterval(UDate from, UDate to)
+: fromDate(from),
+ toDate(to)
+{}
+
+
+DateInterval::~DateInterval(){}
+
+
+DateInterval::DateInterval(const DateInterval& other)
+: UObject(other) {
+ *this = other;
+}
+
+
+DateInterval&
+DateInterval::operator=(const DateInterval& other) {
+ if ( this != &other ) {
+ fromDate = other.fromDate;
+ toDate = other.toDate;
+ }
+ return *this;
+}
+
+
+DateInterval*
+DateInterval::clone() const {
+ return new DateInterval(*this);
+}
+
+
+UBool
+DateInterval::operator==(const DateInterval& other) const {
+ return ( fromDate == other.fromDate && toDate == other.toDate );
+}
+
+
+U_NAMESPACE_END
+
Modified: trunk/source/common/mutex.cpp
===================================================================
--- trunk/source/common/mutex.cpp 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/common/mutex.cpp 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,18 +1,18 @@
-/**
-*******************************************************************************
-* Copyright (C) 2008, International Business Machines Corporation. *
-* All Rights Reserved. *
-*******************************************************************************
-*/
-
-#include "unicode/utypes.h"
-
-#if UCONFIG_NO_SERVICE
-
-/* If UCONFIG_NO_SERVICE, then there is no invocation of Mutex elsewhere in
- common, so add one here to force an export */
-#include "mutex.h"
-static Mutex *aMutex = 0;
-
-/* UCONFIG_NO_SERVICE */
-#endif
+/**
+*******************************************************************************
+* Copyright (C) 2008, International Business Machines Corporation. *
+* All Rights Reserved. *
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if UCONFIG_NO_SERVICE
+
+/* If UCONFIG_NO_SERVICE, then there is no invocation of Mutex elsewhere in
+ common, so add one here to force an export */
+#include "mutex.h"
+static Mutex *aMutex = 0;
+
+/* UCONFIG_NO_SERVICE */
+#endif
Modified: trunk/source/common/uloc.c
===================================================================
--- trunk/source/common/uloc.c 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/common/uloc.c 2009-07-02 19:32:00 UTC (rev 214)
@@ -146,7 +146,7 @@
"lah", "lam", "lb", "lez", "lg", "li", "ln", "lo", "lol",
"loz", "lt", "lu", "lua", "lui", "lun", "luo", "lus",
"lv", "mad", "mag", "mai", "mak", "man", "map", "mas",
- "mdf", "mdr", "men", "mg", "mga", "mh", "mi", "mic", "min",
+ "mdf", "mdr", "men", "mfe", "mg", "mga", "mh", "mi", "mic", "min",
"mis", "mk", "mkh", "ml", "mn", "mnc", "mni", "mno",
"mo", "moh", "mos", "mr", "ms", "mt", "mul", "mun",
"mus", "mwl", "mwr", "my", "myn", "myv", "na", "nah", "nai", "nap",
@@ -262,8 +262,8 @@
"loz", "lit", "lub", "lua", "lui", "lun", "luo", "lus",
/* "lv", "mad", "mag", "mai", "mak", "man", "map", "mas", */
"lav", "mad", "mag", "mai", "mak", "man", "map", "mas",
-/* "mdf", "mdr", "men", "mg", "mga", "mh", "mi", "mic", "min", */
- "mdf", "mdr", "men", "mlg", "mga", "mah", "mri", "mic", "min",
+/* "mdf", "mdr", "men", "mfe", "mg", "mga", "mh", "mi", "mic", "min", */
+ "mdf", "mdr", "men", "mfe", "mlg", "mga", "mah", "mri", "mic", "min",
/* "mis", "mk", "mkh", "ml", "mn", "mnc", "mni", "mno", */
"mis", "mkd", "mkh", "mal", "mon", "mnc", "mni", "mno",
/* "mo", "moh", "mos", "mr", "ms", "mt", "mul", "mun", */
Modified: trunk/source/common/unicode/dtintrv.h
===================================================================
--- trunk/source/common/unicode/dtintrv.h 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/common/unicode/dtintrv.h 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,158 +1,158 @@
-/*
-*******************************************************************************
-* Copyright (C) 2008-2009, International Business Machines Corporation and
-* others. All Rights Reserved.
-*******************************************************************************
-*
-* File DTINTRV.H
-*
-*******************************************************************************
-*/
-
-#ifndef __DTINTRV_H__
-#define __DTINTRV_H__
-
-#include "unicode/utypes.h"
-#include "unicode/uobject.h"
-
-/**
- * \file
- * \brief C++ API: Date Interval data type
- */
-
-
-U_NAMESPACE_BEGIN
-
-
-/**
- * This class represents a date interval.
- * It is a pair of UDate representing from UDate 1 to UDate 2.
- * @stable ICU 4.0
-**/
-class U_COMMON_API DateInterval : public UObject {
-public:
-
- /**
- * Construct a DateInterval given a from date and a to date.
- * @param fromDate The from date in date interval.
- * @param toDate The to date in date interval.
- * @stable ICU 4.0
- */
- DateInterval(UDate fromDate, UDate toDate);
-
- /**
- * destructor
- * @stable ICU 4.0
- */
- virtual ~DateInterval();
-
- /**
- * Get the from date.
- * @return the from date in dateInterval.
- * @stable ICU 4.0
- */
- UDate getFromDate() const;
-
- /**
- * Get the to date.
- * @return the to date in dateInterval.
- * @stable ICU 4.0
- */
- UDate getToDate() const;
-
-
- /**
- * Return the class ID for this class. This is useful only for comparing to
- * a return value from getDynamicClassID(). For example:
- * <pre>
- * . Base* polymorphic_pointer = createPolymorphicObject();
- * . if (polymorphic_pointer->getDynamicClassID() ==
- * . erived::getStaticClassID()) ...
- * </pre>
- * @return The class ID for all objects of this class.
- * @stable ICU 4.0
- */
- static UClassID U_EXPORT2 getStaticClassID(void);
-
- /**
- * 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 4.0
- */
- virtual UClassID getDynamicClassID(void) const;
-
-
- /**
- * Copy constructor.
- * @stable ICU 4.0
- */
- DateInterval(const DateInterval& other);
-
- /**
- * Default assignment operator
- * @stable ICU 4.0
- */
- DateInterval& operator=(const DateInterval&);
-
- /**
- * Equality operator.
- * @return TRUE if the two DateIntervals are the same
- * @stable ICU 4.0
- */
- virtual UBool operator==(const DateInterval& other) const;
-
- /**
- * Non-equality operator
- * @return TRUE if the two DateIntervals are not the same
- * @stable ICU 4.0
- */
- UBool operator!=(const DateInterval& other) const;
-
-
- /**
- * clone this object.
- * The caller owns the result and should delete it when done.
- * @return a cloned DateInterval
- * @stable ICU 4.0
- */
- virtual DateInterval* clone() const;
-
-private:
- /**
- * Default constructor, not implemented.
- */
- DateInterval();
-
- UDate fromDate;
- UDate toDate;
-
-} ;// end class DateInterval
-
-
-inline UDate
-DateInterval::getFromDate() const {
- return fromDate;
-}
-
-
-inline UDate
-DateInterval::getToDate() const {
- return toDate;
-}
-
-
-inline UBool
-DateInterval::operator!=(const DateInterval& other) const {
- return ( !operator==(other) );
-}
-
-
-U_NAMESPACE_END
-
-#endif
+/*
+*******************************************************************************
+* Copyright (C) 2008-2009, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File DTINTRV.H
+*
+*******************************************************************************
+*/
+
+#ifndef __DTINTRV_H__
+#define __DTINTRV_H__
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+
+/**
+ * \file
+ * \brief C++ API: Date Interval data type
+ */
+
+
+U_NAMESPACE_BEGIN
+
+
+/**
+ * This class represents a date interval.
+ * It is a pair of UDate representing from UDate 1 to UDate 2.
+ * @stable ICU 4.0
+**/
+class U_COMMON_API DateInterval : public UObject {
+public:
+
+ /**
+ * Construct a DateInterval given a from date and a to date.
+ * @param fromDate The from date in date interval.
+ * @param toDate The to date in date interval.
+ * @stable ICU 4.0
+ */
+ DateInterval(UDate fromDate, UDate toDate);
+
+ /**
+ * destructor
+ * @stable ICU 4.0
+ */
+ virtual ~DateInterval();
+
+ /**
+ * Get the from date.
+ * @return the from date in dateInterval.
+ * @stable ICU 4.0
+ */
+ UDate getFromDate() const;
+
+ /**
+ * Get the to date.
+ * @return the to date in dateInterval.
+ * @stable ICU 4.0
+ */
+ UDate getToDate() const;
+
+
+ /**
+ * Return the class ID for this class. This is useful only for comparing to
+ * a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . erived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @stable ICU 4.0
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * 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 4.0
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+
+ /**
+ * Copy constructor.
+ * @stable ICU 4.0
+ */
+ DateInterval(const DateInterval& other);
+
+ /**
+ * Default assignment operator
+ * @stable ICU 4.0
+ */
+ DateInterval& operator=(const DateInterval&);
+
+ /**
+ * Equality operator.
+ * @return TRUE if the two DateIntervals are the same
+ * @stable ICU 4.0
+ */
+ virtual UBool operator==(const DateInterval& other) const;
+
+ /**
+ * Non-equality operator
+ * @return TRUE if the two DateIntervals are not the same
+ * @stable ICU 4.0
+ */
+ UBool operator!=(const DateInterval& other) const;
+
+
+ /**
+ * clone this object.
+ * The caller owns the result and should delete it when done.
+ * @return a cloned DateInterval
+ * @stable ICU 4.0
+ */
+ virtual DateInterval* clone() const;
+
+private:
+ /**
+ * Default constructor, not implemented.
+ */
+ DateInterval();
+
+ UDate fromDate;
+ UDate toDate;
+
+} ;// end class DateInterval
+
+
+inline UDate
+DateInterval::getFromDate() const {
+ return fromDate;
+}
+
+
+inline UDate
+DateInterval::getToDate() const {
+ return toDate;
+}
+
+
+inline UBool
+DateInterval::operator!=(const DateInterval& other) const {
+ return ( !operator==(other) );
+}
+
+
+U_NAMESPACE_END
+
+#endif
Deleted: trunk/source/common/unicode/uspoof.h
===================================================================
--- trunk/source/common/unicode/uspoof.h 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/common/unicode/uspoof.h 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,553 +0,0 @@
-/*
-***************************************************************************
-* Copyright (C) 2008, International Business Machines Corporation
-* and others. All Rights Reserved.
-***************************************************************************
-* file name: uspoof.h
-* encoding: US-ASCII
-* tab size: 8 (not used)
-* indentation:4
-*
-* created on: 2008Feb13
-* created by: Andy Heninger
-*
-* Unicode Spoof Detection
-*/
-
-/**
- * \file
- * \brief C API: Unicode Spoof Detection
- *
- * <p>C API for Unicode Security and Spoofing Detection</p>
- *
- * These functions are intended to check strings, typically
- * identifiers or URLs, for the presence of combinations of
- * characters that are likely to be visually confusing -
- * for cases where the displayed form of an identifier may
- * not be what it appears to be.
- *
- * Unicode security considerations, and descriptions of the checks
- * performed by these functions, are describe in
- * Unicode Technical Report #36, http://unicode.org/reports/tr36, and
- * Unicode Technical Standard #39, http://unicode.org/reports/tr39
- */
-#ifndef USPOOF_H
-#define USPOOF_H
-
-#include "unicode/utypes.h"
-#include "unicode/uset.h"
-
-#ifdef XP_CPLUSPLUS
-#include "unicode/unistr.h"
-#include "unicode/uniset.h"
-#endif
-
-
-struct USpoofChecker;
-typedef struct USpoofChecker USpoofChecker;
-
-/**
- * Enum for the kinds of checks that USpoofChecker can perform.
- * These enum values are used both to select the set of checks that
- * will be performed, and to report results from the check function.
- *
- * @draft ICU 4.0
- */
-typedef enum USpoofChecks {
- USPOOF_SINGLE_SCRIPT_CONFUSABLE = 1,
- USPOOF_MIXED_SCRIPT_CONFUSABLE = 2,
- USPOOF_WHOLE_SCRIPT_CONFUSABLE = 4,
- USPOOF_SECURE_ID = 8,
- USPOOF_MIXED_SCRIPT = 16,
- USPOOF_LOCALE_LIMIT = 32,
- USPOOF_CHAR_LIMIT = 64,
- USPOOF_ALL_CHECKS = 0x7f
- };
-
-
-/**
- * Create a Unicode Spoof Checker, configured to perform all
- * checks except for USPOOF_LOCALE_LIMIT and USPOOF_CHAR_LIMIT.
- * Note that additional checks may be added in the future,
- * resulting in the changes to the default checking behavior.
- *
- * @param status The error code, set if this function encounters a problem.
- * @return the newly created Spoof Checker
- * @draft ICU 4.0
- */
-U_DRAFT USpoofChecker * U_EXPORT2
-uspoof_open(UErrorCode *status);
-
-
-/**
- * Specify the set of checks that will be performed by the check
- * functions of this Spoof Checker.
- *
- *
- * @param sc The USpoofChecker
- * @checks The set of checks that this spoof checker will perform.
- * The value is a bit set, obtained by OR-ing together
- * values from enum USpoofChecks.
- * @param status The error code, set if this function encounters a problem.
- * @draft ICU 4.0
- *
- */
-U_DRAFT void U_EXPORT2
-uspoof_setChecks(USpoofChecker *sc, int32_t checks, UErrorCode *status);
-
-/**
- * Get the set of checks that this Spoof Checker has been configured to perform.
- *
- * @param sc The USpoofChecker
- * @param status The error code, set if this function encounters a problem.
- * @return The set of checks that this spoof checker will perform.
- * The value is a bit set, obtained by OR-ing together
- * values from enum USpoofChecks.
- * @draft ICU 4.0
- *
- */
-U_DRAFT int32_t U_EXPORT2
-uspoof_getChecks(const USpoofChecker sc, UErrorCode *status);
-
-/**
- * Limit characters that are acceptable in identifiers being checked to those
- * normally used with the languages associated with the specified locales.
- * Any previously specified list of locales is replaced by the new settings.
- *
- * A set of languages is determined from the locale(s), and
- * from those a set of acceptable Unicode scripts is determined.
- * Characters from this set of scripts, along with characters from
- * the "common" and "inherited" Unicode Script categories
- * will be permitted.
- *
- * Supplying an empty string removes all restrictions;
- * characters from any script will be allowed.
- *
- * The USPOOF_LOCALE_LIMIT test is automatically enabled for this
- * USpoofChecker when calling this function with a non-empty set
- * of locales.
- *
- * @param sc The USpoofChecker
- * @param localesList A list list of locales, from which the language
- * and associated script are extracted. The list
- * list has the format of an HTTP Accept-Language
- * header, and .
- * @param status The error code, set if this function encounters a problem.
- * @draft ICU 4.0
- */
-U_DRAFT void U_EXPORT2
-uspoof_setAllowedLocales(USpoofChecker *sc, const char *localesList, UErrorCode *status);
-
-/**
- * Get a list of locales for the scripts that are acceptable in strings
- * to be checked. If no limitations on scripts have been specified,
- * an empty string will be returned.
- *
- * The format of the returned list is that of an HTTP Accept-Language
- * header field, but it may not be identical to the original string passed
- * to uspoof_setAllowedLocales(); the string may be
- * reformatted, and information other than languages from the originally
- * specified HTTP header may be omitted.
- *
- * @param sc The USpoofChecker
- * @param status The error code, set if this function encounters a problem.
- * @return A string containing a list of locales corresponding
- * to the acceptable scripts, formatted like an
- * HTTP Accept Language value.
- *
- * @draft ICU 4.0
- */
-U_DRAFT const char * U_EXPORT2
-uspoof_getAllowedLocales(USpoofChecker *sc, UErrorCode *status);
-
-
-/**
- * Limit the acceptable characters to those specified by a Unicode Set.
- * Any previously specified character limit is
- * is replaced by the new settings.
- *
- * The USPOOF_CHAR_LIMIT test is automatically enabled for this
- * USpoofChecker by this function.
- *
- * @param sc The USpoofChecker
- * @param chars A Unicode Set containing the list of
- * charcters that are permitted. Ownership of the set
- * remains with the caller. The incoming set is cloned by
- * this function, so there are no restrictions on modifying
- * or deleting the USet after calling this function.
- * @param status The error code, set if this function encounters a problem.
- */
-U_DRAFT void U_EXPORT2
-uspoof_setAllowedChars(USpoofChecker *sc, const USet *chars, UErrorCode *status);
-
-
-/**
- * Get a USet for the characters permitted in an identifier.
- * This corresponds to the limits imposed by the Set Allowed Characters
- * functions. Limitations imposed by other checks will not be
- * reflected in the set returned by this function.
- *
- * The returned set will be frozen, meaning that it cannot be modified
- * by the caller.
- *
- * Ownership of the returned set remains with the Spoof Detector. The
- * returned set will become invalid if the spoof detector is closed,
- * or if a new set of allowed characters is specified.
- *
- *
- * @param sc The USpoofChecker
- * @param chars A Unicode Set containing the complete list of
- * charcters that are permitted. Ownership of the set
- * remains with the caller. The incoming set is cloned by
- * this function, so there are no restrictions on modifying
- * or deleting the USet after calling this function.
- * @param status The error code, set if this function encounters a problem.
- * @return A USet containing the characters that are permitted by
- * the USPOOF_CHAR_LIMIT test.
- */
-U_DRAFT const USet * U_EXPORT2
-uspoof_getAllowedChars(USpoofChecker *sc, UErrorCode *status);
-
-
-#ifdef XP_CPLUSPLUS
-/**
- * Limit the acceptable characters to those specified by a Unicode Set.
- * Any previously specified character limit is
- * is replaced by the new settings.
- *
- * The USPOOF_CHAR_LIMIT test is automatically enabled for this
- * USoofChecker by this function.
- *
- * @param sc The USpoofChecker
- * @param chars A Unicode Set containing the list of
- * charcters that are permitted. Ownership of the set
- * remains with the caller. The incoming set is cloned by
- * this function, so there are no restrictions on modifying
- * or deleting the USet after calling this function.
- * @param status The error code, set if this function encounters a problem.
- */
-U_DRAFT void U_EXPORT2
-uspoof_setAllowedUnicodeSet(USpoofChecker *sc, const UnicodeSet *chars, UErrorCode *status);
-
-
-/**
- * Get a UnicodeSet for the characters permitted in an identifier.
- * This corresponds to the limits imposed by the Set Allowed Characters /
- * UnicodeSet functions. Limitations imposed by other checks will not be
- * reflected in the set returned by this function.
- *
- * The returned set will be frozen, meaning that it cannot be modified
- * by the caller.
- *
- * Ownership of the returned set remains with the Spoof Detector. The
- * returned set will become invalid if the spoof detector is closed,
- * or if a new set of allowed characters is specified.
- *
- *
- * @param sc The USpoofChecker
- * @param status The error code, set if this function encounters a problem.
- * @return A UnicodeSet containing the characters that are permitted by
- * the USPOOF_CHAR_LIMIT test.
- */
-U_DRAFT const UnicodeSet * U_EXPORT2
-uspoof_getAllowedUnicodeSet(USpoofChecker *sc, UErrorCode *status);
-#endif
-
-
-/**
- * Check the specified string for possible security issues.
- * The text to be checked will typically be an indentifier of some sort.
- * The set of checks to be performed is specified with uspoof_setChecks().
- *
- * @param sc The USpoofChecker
- * @param text The string to be checked for possible security issues,
- * in UTF-16 format.
- * @param length the length of the string to be checked, expressed in
- * 16 bit UTF-16 code units, or -1 if the string is
- * zero terminated.
- * @param status The error code, set if an error occured while attempting to
- * perform the check.
- * Spoofing or security issues detected with the input string are
- * not reported here, but through the function's return value.
- * @return An integer value with bits set for any potential security
- * or spoofing issues detected. The bits are defined by
- * enum USpoofChecks. Zero is returned if no issues
- * are found with the input string.
- * @draft ICU 4.0
- */
-U_DRAFT int32_t U_EXPORT2
-uspoof_check(const USpoofChecker *sc, const UChar *text, int32_t length, UErrorCode *status);
-
-/**
- * Check the specified string for possible security issues.
- * The text to be checked will typically be an indentifier of some sort.
- * The set of checks to be performed is specified with uspoof_setChecks().
- *
- * @param sc The USpoofChecker
- * @param text The string to be checked for possible security issues,
- * in UTF-16 format.
- * @param length the length of the string to be checked, expressed in
- * 16 bit UTF-16 code units, or -1 if the string is
- * zero terminated.
- * @param status The error code, set if an error occured while attempting to
- * perform the check.
- * Spoofing or security issues detected with the input string are
- * not reported here, but through the function's return value.
- * @return An integer value with bits set for any potential security
- * or spoofing issues detected. The bits are defined by
- * enum USpoofChecks. Zero is returned if no issues
- * are found with the input string.
- * @draft ICU 4.0
- */
-U_DRAFT int32_t U_EXPORT2
-uspoof_check(const USpoofChecker *sc, const UChar *text, int32_t length, UErrorCode *status);
-
-
-/**
- * Check the specified string for possible security issues.
- * The text to be checked will typically be an indentifier of some sort.
- * The set of checks to be performed is specified with uspoof_setChecks().
- *
- * @param sc The USpoofChecker
- * @param text A UTF-8 string to be checked for possible security issues.
- * @param length the length of the string to be checked, or -1 if the string is
- * zero terminated.
- * @param status The error code, set if an error occured while attempting to
- * perform the check.
- * Spoofing or security issues detected with the input string are
- * not reported here, but through the function's return value.
- * @return An integer value with bits set for any potential security
- * or spoofing issues detected. The bits are defined by
- * enum USpoofChecks. Zero is returned if no issues
- * are found with the input string.
- * @draft ICU 4.0
- */
-U_DRAFT int32_t U_EXPORT2
-uspoof_checkUTF8(const USpoofChecker *sc, const char *text, int32_t length, UErrorCode *status);
-
-
-#ifdef XP_CPLUSPLUS
-/**
- * Check the specified string for possible security issues.
- * The text to be checked will typically be an indentifier of some sort.
- * The set of checks to be performed is specified with uspoof_setChecks().
- *
- * @param sc The USpoofChecker
- * @param text A UnicodeString to be checked for possible security issues.
- * @param status The error code, set if an error occured while attempting to
- * perform the check.
- * Spoofing or security issues detected with the input string are
- * not reported here, but through the function's return value.
- * @return An integer value with bits set for any potential security
- * or spoofing issues detected. The bits are defined by
- * enum USpoofChecks. Zero is returned if no issues
- * are found with the input string.
- * @draft ICU 4.0
- */
-U_DRAFT int32_t U_EXPORT2
-uspoof_checkUnicodeString(const USpoofChecker *sc,
- const U_NAMESPACE_QUALIFIER UnicodeString &text,
- int32_t length, UErrorCode *status);
-
-#endif
-
-
-/**
- * Check the whether two specified strings are visually confusable.
- * The types of confusability to be tested - single script, mixed script,
- * or whole script - are determined by the check options set for the
- * USpoofChecker.
- *
- * @param sc The USpoofChecker
- * @param s1 The first of the two strings to be compared for
- * confusability. The strings are in UTF-16 format.
- * @param length1 the length of the first string, expressed in
- * 16 bit UTF-16 code units, or -1 if the string is
- * zero terminated.
- * @param s2 The second of the two strings to be compared for
- * confusability. The strings are in UTF-16 format.
- * @param length2 The length of the second string, expressed in
- * 16 bit UTF-16 code units, or -1 if the string is
- * zero terminated.
- * @param status The error code, set if an error occured while attempting to
- * perform the check.
- * Confusability of the strings is not reported here,
- * but through this function's return value.
- * @return An integer value with bit(s) set corresponding to
- * the type of confusability found, as defined by
- * enum USpoofChecks. Zero is returned if the strings
- * are not confusable.
- * @draft ICU 4.0
- */
-U_DRAFT int32_t U_EXPORT2
-uspoof_areConfusable(const USpoofChecker *sc,
- const UChar *s1, int32_t length1,
- const UChar *s2, int32_t length2,
- UErrorCode *status);
-
-
-
-/**
- * Check the whether two specified strings are visually confusable.
- * The types of confusability to be tested - single script, mixed script,
- * or whole script - are determined by the check options set for the
- * USpoofChecker.
- *
- * @param sc The USpoofChecker
- * @param s1 The first of the two strings to be compared for
- * confusability. The strings are in UTF-8 format.
- * @param length1 the length of the first string, in bytes, or -1
- * if the string is zero terminated.
- * @param s2 The second of the two strings to be compared for
- * confusability. The strings are in UTF-18 format.
- * @param length2 The length of the second string in bytes, or -1
- * if the string is zero terminated.
- * @param status The error code, set if an error occured while attempting to
- * perform the check.
- * Confusability of the strings is not reported here,
- * but through this function's return value.
- * @return An integer value with bit(s) set corresponding to
- * the type of confusability found, as defined by
- * enum USpoofChecks. Zero is returned if the strings
- * are not confusable.
- * @draft ICU 4.0
- */
-U_DRAFT int32_t U_EXPORT2
-uspoof_areConfusableUTF8(const USpoofChecker *sc,
- const char *s1, int32_t length1,
- const char *s2, int32_t length2,
- UErrorCode *status);
-
-
-
-
-#ifdef XP_CPLUSPLUS
-/**
- * Check the whether two specified strings are visually confusable.
- * The types of confusability to be tested - single script, mixed script,
- * or whole script - are determined by the check options set for the
- * USpoofChecker.
- *
- * @param sc The USpoofChecker
- * @param s1 The first of the two strings to be compared for
- * confusability. The strings are in UTF-8 format.
- * @param s2 The second of the two strings to be compared for
- * confusability. The strings are in UTF-18 format.
- * @param status The error code, set if an error occured while attempting to
- * perform the check.
- * Confusability of the strings is not reported here,
- * but through this function's return value.
- * @return An integer value with bit(s) set corresponding to
- * the type of confusability found, as defined by
- * enum USpoofChecks. Zero is returned if the strings
- * are not confusable.
- * @draft ICU 4.0
- */
-U_DRAFT int32_t U_EXPORT2
-uspoof_areConfusableUnicodeString(const USpoofChecker *sc,
- const U_NAMESPACE_QUALIFIER UnicodeString &s1,
- const U_NAMESPACE_QUALIFIER UnicodeString &s2,
- UErrorCode *status);
-#endif
-
-
-/**
- * Get the "skeleton" for an identifier string.
- * Skeletons are a transformation of the input string;
- * Two strings are confusable if their skeletons are identical.
- * See Unicode UAX 39 for additional information.
- *
- * Using skeletons directly makes it possible to quickly check
- * whether an identifier is confusable with any of some large
- * set of existing identifiers, by creating an efficiently
- * searchable collection of the skeletons.
- *
- * @param sc The USpoofChecker
- * @param s The input string whose skeleton will be computed.
- * @param length The length of the input string, expressed in 16 bit
- * UTF-16 code units, or -1 if the string is zero terminated.
- * @param dest The output buffer, to receive the skeleton string.
- * @param destCapacity The length of the output buffer, in 16 bit units.
- * The destCapacity may be zero, in which case the function will
- * return the actual length of the skeleton.
- * @param status The error code, set if an error occured while attempting to
- * perform the check.
- * @return The length of the skeleton string. The returned length
- * is always that of the complete skeleton, even when the
- * supplied buffer is too small (or of zero length)
- *
- * @draft ICU 4.0
- */
-U_DRAFT int32_t U_EXPORT2
-uspoof_getSkeleton(const USpoofChecker *sc,
- const UChar *s, int32_t length,
- UChar *dest, int32_t destCapacity,
- UErrorCode *status);
-
-/**
- * Get the "skeleton" for an identifier string.
- * Skeletons are a transformation of the input string;
- * Two strings are confusable if their skeletons are identical.
- * See Unicode UAX 39 for additional information.
- *
- * Using skeletons directly makes it possible to quickly check
- * whether an identifier is confusable with any of some large
- * set of existing identifiers, by creating an efficiently
- * searchable collection of the skeletons.
- *
- * @param sc The USpoofChecker
- * @param s The UTF-8 format input string whose skeleton will be computed.
- * @param length The length of the input string, in bytes,
- * or -1 if the string is zero terminated.
- * @param dest The output buffer, to receive the skeleton string.
- * @param destCapacity The length of the output buffer, in bytes.
- * The destCapacity may be zero, in which case the function will
- * return the actual length of the skeleton.
- * @param status The error code, set if an error occured while attempting to
- * perform the check.
- * @return The length of the skeleton string, in bytes. The returned length
- * is always that of the complete skeleton, even when the
- * supplied buffer is too small (or of zero length)
- *
- * @draft ICU 4.0
- */
-U_DRAFT int32_t U_EXPORT2
-uspoof_getSkeletonUTF8(const USpoofChecker *sc,
- const char *s, int32_t length,
- char *dest, int32_t destCapacity,
- UErrorCode *status);
-
-#ifdef XP_CPLUSPLUS
-/**
- * Get the "skeleton" for an identifier string.
- * Skeletons are a transformation of the input string;
- * Two strings are confusable if their skeletons are identical.
- * See Unicode UAX 39 for additional information.
- *
- * Using skeletons directly makes it possible to quickly check
- * whether an identifier is confusable with any of some large
- * set of existing identifiers, by creating an efficiently
- * searchable collection of the skeletons.
- *
- * @param sc The USpoofChecker
- * @param s The input string whose skeleton will be computed.
- * @param dest The output string, to receive the skeleton string.
- * @param destCapacity The length of the output buffer, in bytes.
- * The destCapacity may be zero, in which case the function will
- * return the actual length of the skeleton.
- * @param status The error code, set if an error occured while attempting to
- * perform the check.
- * @return A reference to the destination (skeleton) string.
- *
- * @draft ICU 4.0
- */
-U_DRAFT UnicodeString & U_EXPORT2
-uspoof_getSkeletonUnicodeString(const USpoofChecker *sc,
- const UnicodeString &s,
- UnicodeString &dest,
- UErrorCode *status);
-#endif
-
-#endif
-
-
Modified: trunk/source/common/unicode/uversion.h
===================================================================
--- trunk/source/common/unicode/uversion.h 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/common/unicode/uversion.h 2009-07-02 19:32:00 UTC (rev 214)
@@ -74,14 +74,14 @@
* This value will change in the subsequent releases of ICU
* @stable ICU 2.4
*/
-#define U_ICU_VERSION_PATCHLEVEL_NUM 0
+#define U_ICU_VERSION_PATCHLEVEL_NUM 1
/** The current ICU build level version as an integer.
* This value is for use by ICU clients. It defaults to 0.
* @stable ICU 4.0
*/
#ifndef U_ICU_VERSION_BUILDLEVEL_NUM
-#define U_ICU_VERSION_BUILDLEVEL_NUM 1
+#define U_ICU_VERSION_BUILDLEVEL_NUM 0
#endif
/** Glued version suffix for renamers
@@ -95,7 +95,7 @@
* This value will change in the subsequent releases of ICU
* @stable ICU 2.4
*/
-#define U_ICU_VERSION "4.2.0.1"
+#define U_ICU_VERSION "4.2.1"
/** The current ICU library major/minor version as a string without dots, for library name suffixes.
* This value will change in the subsequent releases of ICU
Modified: trunk/source/config/gmakever.mk
===================================================================
--- trunk/source/config/gmakever.mk 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/config/gmakever.mk 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,20 +1,20 @@
-## -*-makefile-*-
-#******************************************************************************
-# Copyright (C) 2008-2009, International Business Machines
-# Corporation and others. All Rights Reserved.
-#******************************************************************************
-# Make sure we have the right version of Make.
-
-at_least=3.80
-latest_a=$(firstword $(sort $(MAKE_VERSION) $(at_least)))
-
-ifneq ($(at_least),$(latest_a))
-err:
- @echo "ERROR: $(MAKE_VERSION) - too old, please upgrade to at least $(at_least)"
- @false
-else
-ok:
- @echo "$(MAKE_VERSION) (we wanted at least $(at_least))"
- @true
-endif
-
+## -*-makefile-*-
+#******************************************************************************
+# Copyright (C) 2008-2009, International Business Machines
+# Corporation and others. All Rights Reserved.
+#******************************************************************************
+# Make sure we have the right version of Make.
+
+at_least=3.80
+latest_a=$(firstword $(sort $(MAKE_VERSION) $(at_least)))
+
+ifneq ($(at_least),$(latest_a))
+err:
+ @echo "ERROR: $(MAKE_VERSION) - too old, please upgrade to at least $(at_least)"
+ @false
+else
+ok:
+ @echo "$(MAKE_VERSION) (we wanted at least $(at_least))"
+ @true
+endif
+
Modified: trunk/source/config/make2sh.sed
===================================================================
--- trunk/source/config/make2sh.sed 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/config/make2sh.sed 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,4 +1,4 @@
-# Copyright (C) 1999-2006, International Business Machines Corporation and others. All Rights Reserved.
+# Copyright (C) 1999-2009, International Business Machines Corporation and others. All Rights Reserved.
s%^\([a-zA-Z\._-]*\)[ ]*+=%\1=$(\1) %
s%^[A-Z]*_SO_TARG*%## &%
s%^SHARED_OBJECT.*%## &%
@@ -9,6 +9,7 @@
s@^\([a-zA-Z][-.a-zA-Z_0-9-]*\)[ ]*=[ ]*\(.*\)@\1="\2"@
s@^\([a-zA-Z][-a-zA-Z_0-9-]*\)\.\([a-zA-Z_0-9-]*\)[ ]*=[ ]*\(.*\)@\1_\2=\3@
s@^\([a-zA-Z][-a-zA-Z_0-9-]*\)\-\([a-zA-Z_0-9-]*\)[ ]*=[ ]*\(.*\)@\1_\2=\3@
+s@\${\([a-zA-Z][-a-zA-Z_0-9-]*\)\.\([a-zA-Z_0-9-]*\)}@${\1_\2}@g
s@^\(prefix\)=\(.*\)@default_\1=\2\
if [ "x${\1}" = "x" ]; then \1="$default_\1"; fi@
s@^\(ENABLE_RPATH\)=\(.*\)@default_\1=\2\
Modified: trunk/source/config/pkgdataMakefile.in
===================================================================
--- trunk/source/config/pkgdataMakefile.in 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/config/pkgdataMakefile.in 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,40 +1,40 @@
-## pkgdataMakefile.in for ICU data
-## Copyright (c) 2008, International Business Machines Corporation and
-## others. All Rights Reserved.
-
-## Source directory information
-srcdir = @srcdir@
-top_srcdir = @top_srcdir@
-
-# So that you have $(top_builddir)/config.status
-top_builddir = ..
-
-## All the flags and other definitions are included here.
-include $(top_builddir)/icudefs.mk
-
-OUTPUTFILE=pkgdata.inc
-MIDDLE_SO_TARGET=
-
-all : clean
- @echo GENCCODE_ASSEMBLY_TYPE=$(GENCCODE_ASSEMBLY) >> $(OUTPUTFILE)
- @echo SO=$(SO) >> $(OUTPUTFILE)
- @echo SOBJ=$(SOBJ) >> $(OUTPUTFILE)
- @echo A=$(A) >> $(OUTPUTFILE)
- @echo LIBPREFIX=$(LIBPREFIX) >> $(OUTPUTFILE)
- @echo LIB_EXT_ORDER=$(FINAL_SO_TARGET) >> $(OUTPUTFILE)
- @echo COMPILE="$(COMPILE.c)" >> $(OUTPUTFILE)
- @echo LIBFLAGS="-I$(prefix)/include $(SHAREDLIBCPPFLAGS) $(SHAREDLIBCFLAGS)" >> $(OUTPUTFILE)
- @echo GENLIB="$(SHLIB.c)" >> $(OUTPUTFILE)
- @echo LDICUDTFLAGS=$(LDFLAGSICUDT) >> $(OUTPUTFILE)
- @echo LD_SONAME=$(LD_SONAME) >> $(OUTPUTFILE)
- @echo RPATH_FLAGS=$(RPATH_FLAGS) >> $(OUTPUTFILE)
- @echo BIR_LDFLAGS=$(BIR_LDFLAGS) >> $(OUTPUTFILE)
- @echo AR=$(AR) >> $(OUTPUTFILE)
- @echo ARFLAGS=$(ARFLAGS) >> $(OUTPUTFILE)
- @echo RANLIB=$(RANLIB) >> $(OUTPUTFILE)
- @echo INSTALL_CMD=$(INSTALL-L) >> $(OUTPUTFILE)
-
-
-clean :
- $(RMV) $(OUTPUTFILE)
-
+## pkgdataMakefile.in for ICU data
+## Copyright (c) 2008, International Business Machines Corporation and
+## others. All Rights Reserved.
+
+## Source directory information
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+
+# So that you have $(top_builddir)/config.status
+top_builddir = ..
+
+## All the flags and other definitions are included here.
+include $(top_builddir)/icudefs.mk
+
+OUTPUTFILE=pkgdata.inc
+MIDDLE_SO_TARGET=
+
+all : clean
+ @echo GENCCODE_ASSEMBLY_TYPE=$(GENCCODE_ASSEMBLY) >> $(OUTPUTFILE)
+ @echo SO=$(SO) >> $(OUTPUTFILE)
+ @echo SOBJ=$(SOBJ) >> $(OUTPUTFILE)
+ @echo A=$(A) >> $(OUTPUTFILE)
+ @echo LIBPREFIX=$(LIBPREFIX) >> $(OUTPUTFILE)
+ @echo LIB_EXT_ORDER=$(FINAL_SO_TARGET) >> $(OUTPUTFILE)
+ @echo COMPILE="$(COMPILE.c)" >> $(OUTPUTFILE)
+ @echo LIBFLAGS="-I$(prefix)/include $(SHAREDLIBCPPFLAGS) $(SHAREDLIBCFLAGS)" >> $(OUTPUTFILE)
+ @echo GENLIB="$(SHLIB.c)" >> $(OUTPUTFILE)
+ @echo LDICUDTFLAGS=$(LDFLAGSICUDT) >> $(OUTPUTFILE)
+ @echo LD_SONAME=$(LD_SONAME) >> $(OUTPUTFILE)
+ @echo RPATH_FLAGS=$(RPATH_FLAGS) >> $(OUTPUTFILE)
+ @echo BIR_LDFLAGS=$(BIR_LDFLAGS) >> $(OUTPUTFILE)
+ @echo AR=$(AR) >> $(OUTPUTFILE)
+ @echo ARFLAGS=$(ARFLAGS) >> $(OUTPUTFILE)
+ @echo RANLIB=$(RANLIB) >> $(OUTPUTFILE)
+ @echo INSTALL_CMD=$(INSTALL-L) >> $(OUTPUTFILE)
+
+
+clean :
+ $(RMV) $(OUTPUTFILE)
+
Modified: trunk/source/configure.mk
===================================================================
--- trunk/source/configure.mk 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/configure.mk 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,11 +1,11 @@
-# Copyright (c) 2008-2009, International Business Machines Corporation and others. All Rights Reserved.
-#
-#
-# Makefile for regenerating configure in the face of a bad ^M
-# This should become unnecessary for autoconf past 2.63
-#
-# Usage: MAKE -f configure.mk configure
-
-configure: configure.in ./aclocal.m4
- ( autoconf && mv configure configure.tmp && sed -e 's%^ac_cr=.*%ac_cr=`echo X |tr X "\\015"`%' < configure.tmp > configure && chmod a+rx $@ && rm configure.tmp ) || ( rm $@ ; "echo configure build failed" ; /usr/bin/false )
-
+# Copyright (c) 2008-2009, International Business Machines Corporation and others. All Rights Reserved.
+#
+#
+# Makefile for regenerating configure in the face of a bad ^M
+# This should become unnecessary for autoconf past 2.63
+#
+# Usage: MAKE -f configure.mk configure
+
+configure: configure.in ./aclocal.m4
+ ( autoconf && mv configure configure.tmp && sed -e 's%^ac_cr=.*%ac_cr=`echo X |tr X "\\015"`%' < configure.tmp > configure && chmod a+rx $@ && rm configure.tmp ) || ( rm $@ ; "echo configure build failed" ; /usr/bin/false )
+
Modified: trunk/source/extra/uconv/pkgdataMakefile.in
===================================================================
--- trunk/source/extra/uconv/pkgdataMakefile.in 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/extra/uconv/pkgdataMakefile.in 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,40 +1,40 @@
-## pkgdataMakefile.in for ICU data
-## Copyright (c) 2008-2009, International Business Machines Corporation and
-## others. All Rights Reserved.
-
-## Source directory information
-srcdir = @srcdir@
-top_srcdir = @top_srcdir@
-
-# So that you have $(top_builddir)/config.status
-top_builddir = ../..
-
-## All the flags and other definitions are included here.
-include $(top_builddir)/icudefs.mk
-
-MIDDLE_SO_TARGET=
-
-OUTPUTFILE=pkgdata.inc
-
-all : clean
- @echo GENCCODE_ASSEMBLY_TYPE=$(GENCCODE_ASSEMBLY) >> $(OUTPUTFILE)
- @echo SO=$(SO) >> $(OUTPUTFILE)
- @echo SOBJ=$(SOBJ) >> $(OUTPUTFILE)
- @echo A=$(A) >> $(OUTPUTFILE)
- @echo LIBPREFIX=$(LIBPREFIX) >> $(OUTPUTFILE)
- @echo LIB_EXT_ORDER=$(FINAL_SO_TARGET) >> $(OUTPUTFILE)
- @echo COMPILE="$(COMPILE.c)" >> $(OUTPUTFILE)
- @echo LIBFLAGS="-I$(top_srcdir)/common -I$(top_builddir)/common $(SHAREDLIBCPPFLAGS) $(SHAREDLIBCFLAGS)" >> $(OUTPUTFILE)
- @echo GENLIB="$(SHLIB.c)" >> $(OUTPUTFILE)
- @echo LDICUDTFLAGS=$(LDFLAGSICUDT) >> $(OUTPUTFILE)
- @echo LD_SONAME=$(LD_SONAME) >> $(OUTPUTFILE)
- @echo RPATH_FLAGS=$(RPATH_FLAGS) >> $(OUTPUTFILE)
- @echo BIR_LDFLAGS=$(BIR_LDFLAGS) >> $(OUTPUTFILE)
- @echo AR=$(AR) >> $(OUTPUTFILE)
- @echo ARFLAGS=$(ARFLAGS) >> $(OUTPUTFILE)
- @echo RANLIB=$(RANLIB) >> $(OUTPUTFILE)
- @echo INSTALL_CMD=$(INSTALL_DATA) >> $(OUTPUTFILE)
-
-clean :
- $(RMV) $(OUTPUTFILE)
-
+## pkgdataMakefile.in for ICU data
+## Copyright (c) 2008-2009, International Business Machines Corporation and
+## others. All Rights Reserved.
+
+## Source directory information
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+
+# So that you have $(top_builddir)/config.status
+top_builddir = ../..
+
+## All the flags and other definitions are included here.
+include $(top_builddir)/icudefs.mk
+
+MIDDLE_SO_TARGET=
+
+OUTPUTFILE=pkgdata.inc
+
+all : clean
+ @echo GENCCODE_ASSEMBLY_TYPE=$(GENCCODE_ASSEMBLY) >> $(OUTPUTFILE)
+ @echo SO=$(SO) >> $(OUTPUTFILE)
+ @echo SOBJ=$(SOBJ) >> $(OUTPUTFILE)
+ @echo A=$(A) >> $(OUTPUTFILE)
+ @echo LIBPREFIX=$(LIBPREFIX) >> $(OUTPUTFILE)
+ @echo LIB_EXT_ORDER=$(FINAL_SO_TARGET) >> $(OUTPUTFILE)
+ @echo COMPILE="$(COMPILE.c)" >> $(OUTPUTFILE)
+ @echo LIBFLAGS="-I$(top_srcdir)/common -I$(top_builddir)/common $(SHAREDLIBCPPFLAGS) $(SHAREDLIBCFLAGS)" >> $(OUTPUTFILE)
+ @echo GENLIB="$(SHLIB.c)" >> $(OUTPUTFILE)
+ @echo LDICUDTFLAGS=$(LDFLAGSICUDT) >> $(OUTPUTFILE)
+ @echo LD_SONAME=$(LD_SONAME) >> $(OUTPUTFILE)
+ @echo RPATH_FLAGS=$(RPATH_FLAGS) >> $(OUTPUTFILE)
+ @echo BIR_LDFLAGS=$(BIR_LDFLAGS) >> $(OUTPUTFILE)
+ @echo AR=$(AR) >> $(OUTPUTFILE)
+ @echo ARFLAGS=$(ARFLAGS) >> $(OUTPUTFILE)
+ @echo RANLIB=$(RANLIB) >> $(OUTPUTFILE)
+ @echo INSTALL_CMD=$(INSTALL_DATA) >> $(OUTPUTFILE)
+
+clean :
+ $(RMV) $(OUTPUTFILE)
+
Modified: trunk/source/extra/uconv/uconv.vcproj
===================================================================
--- trunk/source/extra/uconv/uconv.vcproj 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/extra/uconv/uconv.vcproj 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,485 +1,485 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="9.00"
- Name="uconv"
- ProjectGUID="{DBA4088D-F6F9-4F8F-8820-082A4765C16C}"
- TargetFrameworkVersion="131072"
- >
- <Platforms>
- <Platform
- Name="Win32"
- />
- <Platform
- Name="x64"
- />
- </Platforms>
- <ToolFiles>
- </ToolFiles>
- <Configurations>
- <Configuration
- Name="Release|Win32"
- OutputDirectory=".\x86\Release"
- IntermediateDirectory=".\x86\Release"
- ConfigurationType="1"
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- CommandLine="copy "$(TargetPath)" ..\..\..\bin
"
- Outputs="$(ProjectDir)..\..\..\bin\$(TargetFileName)"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- TypeLibraryName=".\x86\Release/uconv.tlb"
- />
- <Tool
- Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="..\..\..\include;..\..\common"
- PreprocessorDefinitions="WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;UCONVMSG_LINK"
- StringPooling="true"
- RuntimeLibrary="2"
- EnableFunctionLevelLinking="true"
- DisableLanguageExtensions="true"
- TreatWChar_tAsBuiltInType="true"
- PrecompiledHeaderFile=".\x86\Release/uconv.pch"
- AssemblerListingLocation=".\x86\Release/"
- ObjectFile=".\x86\Release/"
- ProgramDataBaseFileName=".\x86\Release/"
- WarningLevel="3"
- SuppressStartupBanner="true"
- CompileAs="0"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="NDEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="uconvmsg.lib"
- OutputFile=".\x86\Release/uconv.exe"
- LinkIncremental="1"
- SuppressStartupBanner="true"
- AdditionalLibraryDirectories="x86\Release"
- ProgramDatabaseFile=".\x86\Release/uconv.pdb"
- SubSystem="1"
- RandomizedBaseAddress="1"
- DataExecutionPrevention="0"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory=".\x86\Debug"
- IntermediateDirectory=".\x86\Debug"
- ConfigurationType="1"
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- CommandLine="copy "$(TargetPath)" ..\..\..\bin
"
- Outputs="$(ProjectDir)..\..\..\bin\$(TargetFileName)"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- TypeLibraryName=".\x86\Debug/uconv.tlb"
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories="..\..\..\include;..\..\common"
- PreprocessorDefinitions="WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;UCONVMSG_LINK"
- BasicRuntimeChecks="3"
- RuntimeLibrary="3"
- BufferSecurityCheck="true"
- DisableLanguageExtensions="true"
- TreatWChar_tAsBuiltInType="true"
- PrecompiledHeaderFile=".\x86\Debug/uconv.pch"
- AssemblerListingLocation=".\x86\Debug/"
- ObjectFile=".\x86\Debug/"
- ProgramDataBaseFileName=".\x86\Debug/"
- WarningLevel="3"
- SuppressStartupBanner="true"
- DebugInformationFormat="4"
- CompileAs="0"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_DEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="uconvmsg.lib"
- OutputFile=".\x86\Debug/uconv.exe"
- LinkIncremental="2"
- SuppressStartupBanner="true"
- AdditionalLibraryDirectories="x86\Debug"
- GenerateDebugInformation="true"
- ProgramDatabaseFile=".\x86\Debug/uconv.pdb"
- SubSystem="1"
- RandomizedBaseAddress="1"
- DataExecutionPrevention="0"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- UseFAT32Workaround="true"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Release|x64"
- OutputDirectory=".\x64\Release"
- IntermediateDirectory=".\x64\Release"
- ConfigurationType="1"
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- CommandLine="copy "$(TargetPath)" ..\..\..\bin64
"
- Outputs="$(ProjectDir)..\..\..\bin64\$(TargetFileName)"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- TargetEnvironment="3"
- TypeLibraryName=".\x64\Release/uconv.tlb"
- />
- <Tool
- Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="..\..\..\include;..\..\common"
- PreprocessorDefinitions="WIN64;WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;UCONVMSG_LINK"
- StringPooling="true"
- RuntimeLibrary="2"
- EnableFunctionLevelLinking="true"
- DisableLanguageExtensions="true"
- TreatWChar_tAsBuiltInType="true"
- PrecompiledHeaderFile=".\x64\Release/uconv.pch"
- AssemblerListingLocation=".\x64\Release/"
- ObjectFile=".\x64\Release/"
- ProgramDataBaseFileName=".\x64\Release/"
- WarningLevel="3"
- SuppressStartupBanner="true"
- CompileAs="0"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="NDEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="uconvmsg.lib"
- OutputFile=".\x64\Release/uconv.exe"
- LinkIncremental="1"
- SuppressStartupBanner="true"
- AdditionalLibraryDirectories="x64\Release"
- ProgramDatabaseFile=".\x64\Release/uconv.pdb"
- SubSystem="1"
- TargetMachine="17"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Debug|x64"
- OutputDirectory=".\x64\Debug"
- IntermediateDirectory=".\x64\Debug"
- ConfigurationType="1"
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- CommandLine="copy "$(TargetPath)" ..\..\..\bin64
"
- Outputs="$(ProjectDir)..\..\..\bin64\$(TargetFileName)"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- TargetEnvironment="3"
- TypeLibraryName=".\x64\Debug/uconv.tlb"
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories="..\..\..\include;..\..\common"
- PreprocessorDefinitions="WIN64;WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;UCONVMSG_LINK"
- BasicRuntimeChecks="3"
- RuntimeLibrary="3"
- BufferSecurityCheck="true"
- DisableLanguageExtensions="true"
- TreatWChar_tAsBuiltInType="true"
- PrecompiledHeaderFile=".\x64\Debug/uconv.pch"
- AssemblerListingLocation=".\x64\Debug/"
- ObjectFile=".\x64\Debug/"
- ProgramDataBaseFileName=".\x64\Debug/"
- WarningLevel="3"
- SuppressStartupBanner="true"
- DebugInformationFormat="3"
- CompileAs="0"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_DEBUG"
- Culture="1033"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="uconvmsg.lib"
- OutputFile=".\x64\Debug/uconv.exe"
- LinkIncremental="2"
- SuppressStartupBanner="true"
- AdditionalLibraryDirectories="x64\Debug"
- GenerateDebugInformation="true"
- ProgramDatabaseFile=".\x64\Debug/uconv.pdb"
- SubSystem="1"
- TargetMachine="17"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- UseFAT32Workaround="true"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCWebDeploymentTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Source Files"
- Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
- >
- <File
- RelativePath=".\uconv.cpp"
- >
- </File>
- <File
- RelativePath=".\uwmsg.c"
- >
- </File>
- </Filter>
- <Filter
- Name="Header Files"
- Filter="h;hpp;hxx;hm;inl"
- >
- <File
- RelativePath=".\unicode\uwmsg.h"
- >
- </File>
- </Filter>
- <Filter
- Name="Resource Bundles"
- Filter="txt"
- >
- <File
- RelativePath=".\resources\fr.txt"
- >
- </File>
- <File
- RelativePath=".\resources\root.txt"
- >
- </File>
- </Filter>
- <Filter
- Name="Build Scripts"
- Filter="mak;mk;bat"
- >
- <File
- RelativePath=".\makedata.mak"
- >
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- CommandLine="nmake /nologo /f $(InputName).mak icup="$(ProjectDir)..\..\.." CFG=x86\Release
"
- Outputs="x86\Release/uconvmsg.lib"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- CommandLine="nmake /nologo /f $(InputName).mak icup="$(ProjectDir)..\..\.." CFG=x86\Debug
"
- Outputs="x86\Debug/uconvmsg.lib"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|x64"
- >
- <Tool
- Name="VCCustomBuildTool"
- CommandLine="nmake /nologo /f $(InputName).mak icup="$(ProjectDir)..\..\.." CFG=x64\Release
"
- Outputs="x64\Release/uconvmsg.lib"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Debug|x64"
- >
- <Tool
- Name="VCCustomBuildTool"
- CommandLine="nmake /nologo /f $(InputName).mak icup="$(ProjectDir)..\..\.." CFG=x64\Debug
"
- Outputs="x64\Debug/uconvmsg.lib"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath=".\resfiles.mk"
- >
- </File>
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="uconv"
+ ProjectGUID="{DBA4088D-F6F9-4F8F-8820-082A4765C16C}"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\x86\Release"
+ IntermediateDirectory=".\x86\Release"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy "$(TargetPath)" ..\..\..\bin
"
+ Outputs="$(ProjectDir)..\..\..\bin\$(TargetFileName)"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\x86\Release/uconv.tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\..\include;..\..\common"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;UCONVMSG_LINK"
+ StringPooling="true"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="true"
+ TreatWChar_tAsBuiltInType="true"
+ PrecompiledHeaderFile=".\x86\Release/uconv.pch"
+ AssemblerListingLocation=".\x86\Release/"
+ ObjectFile=".\x86\Release/"
+ ProgramDataBaseFileName=".\x86\Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="uconvmsg.lib"
+ OutputFile=".\x86\Release/uconv.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories="x86\Release"
+ ProgramDatabaseFile=".\x86\Release/uconv.pdb"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\x86\Debug"
+ IntermediateDirectory=".\x86\Debug"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy "$(TargetPath)" ..\..\..\bin
"
+ Outputs="$(ProjectDir)..\..\..\bin\$(TargetFileName)"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\x86\Debug/uconv.tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..\include;..\..\common"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;UCONVMSG_LINK"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="true"
+ DisableLanguageExtensions="true"
+ TreatWChar_tAsBuiltInType="true"
+ PrecompiledHeaderFile=".\x86\Debug/uconv.pch"
+ AssemblerListingLocation=".\x86\Debug/"
+ ObjectFile=".\x86\Debug/"
+ ProgramDataBaseFileName=".\x86\Debug/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="uconvmsg.lib"
+ OutputFile=".\x86\Debug/uconv.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories="x86\Debug"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile=".\x86\Debug/uconv.pdb"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ UseFAT32Workaround="true"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory=".\x64\Release"
+ IntermediateDirectory=".\x64\Release"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy "$(TargetPath)" ..\..\..\bin64
"
+ Outputs="$(ProjectDir)..\..\..\bin64\$(TargetFileName)"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ TypeLibraryName=".\x64\Release/uconv.tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\..\include;..\..\common"
+ PreprocessorDefinitions="WIN64;WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;UCONVMSG_LINK"
+ StringPooling="true"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="true"
+ TreatWChar_tAsBuiltInType="true"
+ PrecompiledHeaderFile=".\x64\Release/uconv.pch"
+ AssemblerListingLocation=".\x64\Release/"
+ ObjectFile=".\x64\Release/"
+ ProgramDataBaseFileName=".\x64\Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="uconvmsg.lib"
+ OutputFile=".\x64\Release/uconv.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories="x64\Release"
+ ProgramDatabaseFile=".\x64\Release/uconv.pdb"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory=".\x64\Debug"
+ IntermediateDirectory=".\x64\Debug"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy "$(TargetPath)" ..\..\..\bin64
"
+ Outputs="$(ProjectDir)..\..\..\bin64\$(TargetFileName)"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ TypeLibraryName=".\x64\Debug/uconv.tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..\include;..\..\common"
+ PreprocessorDefinitions="WIN64;WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;UCONVMSG_LINK"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="true"
+ DisableLanguageExtensions="true"
+ TreatWChar_tAsBuiltInType="true"
+ PrecompiledHeaderFile=".\x64\Debug/uconv.pch"
+ AssemblerListingLocation=".\x64\Debug/"
+ ObjectFile=".\x64\Debug/"
+ ProgramDataBaseFileName=".\x64\Debug/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="uconvmsg.lib"
+ OutputFile=".\x64\Debug/uconv.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories="x64\Debug"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile=".\x64\Debug/uconv.pdb"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ UseFAT32Workaround="true"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+ >
+ <File
+ RelativePath=".\uconv.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\uwmsg.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl"
+ >
+ <File
+ RelativePath=".\unicode\uwmsg.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Bundles"
+ Filter="txt"
+ >
+ <File
+ RelativePath=".\resources\fr.txt"
+ >
+ </File>
+ <File
+ RelativePath=".\resources\root.txt"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Build Scripts"
+ Filter="mak;mk;bat"
+ >
+ <File
+ RelativePath=".\makedata.mak"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="nmake /nologo /f $(InputName).mak icup="$(ProjectDir)..\..\.." CFG=x86\Release
"
+ Outputs="x86\Release/uconvmsg.lib"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="nmake /nologo /f $(InputName).mak icup="$(ProjectDir)..\..\.." CFG=x86\Debug
"
+ Outputs="x86\Debug/uconvmsg.lib"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="nmake /nologo /f $(InputName).mak icup="$(ProjectDir)..\..\.." CFG=x64\Release
"
+ Outputs="x64\Release/uconvmsg.lib"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="nmake /nologo /f $(InputName).mak icup="$(ProjectDir)..\..\.." CFG=x64\Debug
"
+ Outputs="x64\Debug/uconvmsg.lib"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\resfiles.mk"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Modified: trunk/source/i18n/currpinf.cpp
===================================================================
--- trunk/source/i18n/currpinf.cpp 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/i18n/currpinf.cpp 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,370 +1,372 @@
-/*
- *******************************************************************************
- * Copyright (C) 2009, International Business Machines Corporation and *
- * others. All Rights Reserved. *
- *******************************************************************************
- */
-
-#include "unicode/currpinf.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-//#define CURRENCY_PLURAL_INFO_DEBUG 1
-
-#ifdef CURRENCY_PLURAL_INFO_DEBUG
-#include <iostream>
-#endif
-
-
-#include "unicode/locid.h"
-#include "unicode/plurrule.h"
-#include "unicode/ures.h"
-#include "cstring.h"
-#include "hash.h"
-#include "uresimp.h"
-
-U_NAMESPACE_BEGIN
-
-
-static const UChar gNumberPatternSeparator = 0x3B; // ;
-
-U_CDECL_BEGIN
-
-/**
- * @internal ICU 4.2
- */
-static UBool U_CALLCONV ValueComparator(UHashTok val1, UHashTok val2);
-
-U_CDECL_END
-
-UBool
-U_CALLCONV ValueComparator(UHashTok val1, UHashTok val2) {
- const UnicodeString* affix_1 = (UnicodeString*)val1.pointer;
- const UnicodeString* affix_2 = (UnicodeString*)val2.pointer;
- return *affix_1 == *affix_2;
-}
-
-
-
-UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CurrencyPluralInfo)
-
-static const UChar gDefaultCurrencyPluralPattern[] = {'0', '.', '#', '#', ' ', 0xA4, 0xA4, 0xA4, 0};
-static const UChar gTripleCurrencySign[] = {0xA4, 0xA4, 0xA4, 0};
-static const UChar gPluralCountOther[] = {0x6F, 0x74, 0x68, 0x65, 0x72, 0};
-static const UChar gPart0[] = {0x7B, 0x30, 0x7D, 0};
-static const UChar gPart1[] = {0x7B, 0x31, 0x7D, 0};
-
-static const char gNumberPatternsTag[]="NumberPatterns";
-static const char gCurrUnitPtnTag[]="CurrencyUnitPatterns";
-
-CurrencyPluralInfo::CurrencyPluralInfo(UErrorCode& status)
-: fPluralCountToCurrencyUnitPattern(NULL),
- fPluralRules(NULL),
- fLocale(NULL) {
- initialize(Locale::getDefault(), status);
-}
-
-CurrencyPluralInfo::CurrencyPluralInfo(const Locale& locale, UErrorCode& status)
-: fPluralCountToCurrencyUnitPattern(NULL),
- fPluralRules(NULL),
- fLocale(NULL) {
- initialize(locale, status);
-}
-
-CurrencyPluralInfo::CurrencyPluralInfo(const CurrencyPluralInfo& info)
-: UObject(info),
- fPluralCountToCurrencyUnitPattern(NULL),
- fPluralRules(NULL),
- fLocale(NULL) {
- *this = info;
-}
-
-
-CurrencyPluralInfo&
-CurrencyPluralInfo::operator=(const CurrencyPluralInfo& info) {
- if (this == &info) {
- return *this;
- }
-
- deleteHash(fPluralCountToCurrencyUnitPattern);
- UErrorCode status = U_ZERO_ERROR;
- fPluralCountToCurrencyUnitPattern = initHash(status);
- copyHash(info.fPluralCountToCurrencyUnitPattern,
- fPluralCountToCurrencyUnitPattern, status);
- if ( U_FAILURE(status) ) {
- return *this;
- }
-
- delete fPluralRules;
- delete fLocale;
- if (info.fPluralRules) {
- fPluralRules = info.fPluralRules->clone();
- } else {
- fPluralRules = NULL;
- }
- if (info.fLocale) {
- fLocale = info.fLocale->clone();
- } else {
- fLocale = NULL;
- }
- return *this;
-}
-
-
-CurrencyPluralInfo::~CurrencyPluralInfo() {
- deleteHash(fPluralCountToCurrencyUnitPattern);
- fPluralCountToCurrencyUnitPattern = NULL;
- delete fPluralRules;
- delete fLocale;
- fPluralRules = NULL;
- fLocale = NULL;
-}
-
-UBool
-CurrencyPluralInfo::operator==(const CurrencyPluralInfo& info) const {
-#ifdef CURRENCY_PLURAL_INFO_DEBUG
- if (*fPluralRules == *info.fPluralRules) {
- std::cout << "same plural rules\n";
- }
- if (*fLocale == *info.fLocale) {
- std::cout << "same locale\n";
- }
- if (fPluralCountToCurrencyUnitPattern->equals(*info.fPluralCountToCurrencyUnitPattern)) {
- std::cout << "same pattern\n";
- }
-#endif
- return *fPluralRules == *info.fPluralRules &&
- *fLocale == *info.fLocale &&
- fPluralCountToCurrencyUnitPattern->equals(*info.fPluralCountToCurrencyUnitPattern);
-}
-
-
-CurrencyPluralInfo*
-CurrencyPluralInfo::clone() const {
- return new CurrencyPluralInfo(*this);
-}
-
-const PluralRules*
-CurrencyPluralInfo::getPluralRules() const {
- return fPluralRules;
-}
-
-UnicodeString&
-CurrencyPluralInfo::getCurrencyPluralPattern(const UnicodeString& pluralCount,
- UnicodeString& result) const {
- const UnicodeString* currencyPluralPattern =
- (UnicodeString*)fPluralCountToCurrencyUnitPattern->get(pluralCount);
- if (currencyPluralPattern == NULL) {
- // fall back to "other"
- if (pluralCount.compare(gPluralCountOther)) {
- currencyPluralPattern =
- (UnicodeString*)fPluralCountToCurrencyUnitPattern->get(gPluralCountOther);
- }
- if (currencyPluralPattern == NULL) {
- // no currencyUnitPatterns defined,
- // fallback to predefined defult.
- // This should never happen when ICU resource files are
- // available, since currencyUnitPattern of "other" is always
- // defined in root.
- result = UnicodeString(gDefaultCurrencyPluralPattern);
- return result;
- }
- }
- result = *currencyPluralPattern;
- return result;
-}
-
-const Locale&
-CurrencyPluralInfo::getLocale() const {
- return *fLocale;
-}
-
-void
-CurrencyPluralInfo::setPluralRules(const UnicodeString& ruleDescription,
- UErrorCode& status) {
- if (U_SUCCESS(status)) {
- fPluralRules = PluralRules::createRules(ruleDescription, status);
- }
-}
-
-
-void
-CurrencyPluralInfo::setCurrencyPluralPattern(const UnicodeString& pluralCount,
- const UnicodeString& pattern,
- UErrorCode& status) {
- if (U_SUCCESS(status)) {
- fPluralCountToCurrencyUnitPattern->put(pluralCount, new UnicodeString(pattern), status);
- }
-}
-
-
-void
-CurrencyPluralInfo::setLocale(const Locale& loc, UErrorCode& status) {
- initialize(loc, status);
-}
-
-
-void
-CurrencyPluralInfo::initialize(const Locale& loc, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return;
- }
- delete fLocale;
- fLocale = loc.clone();
- fPluralRules = PluralRules::forLocale(loc, status);
- setupCurrencyPluralPattern(loc, status);
-}
-
-
-void
-CurrencyPluralInfo::setupCurrencyPluralPattern(const Locale& loc, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return;
- }
-
- fPluralCountToCurrencyUnitPattern = initHash(status);
- if (U_FAILURE(status)) {
- return;
- }
-
- UErrorCode ec = U_ZERO_ERROR;
- UResourceBundle *rb = ures_open(NULL, loc.getName(), &ec);
- UResourceBundle *numberPatterns = ures_getByKey(rb, gNumberPatternsTag, NULL, &ec);
- int32_t ptnLen;
- // TODO: 0 to be NumberFormat::fNumberStyle
- const UChar* numberStylePattern = ures_getStringByIndex(numberPatterns, 0,
- &ptnLen, &ec);
- int32_t numberStylePatternLen = ptnLen;
- const UChar* negNumberStylePattern = NULL;
- int32_t negNumberStylePatternLen = 0;
- // TODO: Java
- // parse to check whether there is ";" separator in the numberStylePattern
- UBool hasSeparator = false;
- for (int32_t styleCharIndex = 0; styleCharIndex < ptnLen; ++styleCharIndex) {
- if (numberStylePattern[styleCharIndex] == gNumberPatternSeparator) {
- hasSeparator = true;
- // split the number style pattern into positive and negative
- negNumberStylePattern = numberStylePattern + styleCharIndex + 1;
- negNumberStylePatternLen = ptnLen - styleCharIndex - 1;
- numberStylePatternLen = styleCharIndex;
- }
- }
- ures_close(numberPatterns);
-
- if (U_FAILURE(ec)) {
- ures_close(rb);
- return;
- }
-
- UResourceBundle *currencyRes = ures_getByKeyWithFallback(rb, gCurrUnitPtnTag, NULL, &ec);
-
-#ifdef CURRENCY_PLURAL_INFO_DEBUG
- std::cout << "in set up\n";
-#endif
- StringEnumeration* keywords = fPluralRules->getKeywords(ec);
- if (U_SUCCESS(ec)) {
- const char* pluralCount;
- while ((pluralCount = keywords->next(NULL, ec)) != NULL) {
- if ( U_SUCCESS(ec) ) {
- int32_t ptnLen;
- UErrorCode err = U_ZERO_ERROR;
- const UChar* patternChars = ures_getStringByKeyWithFallback(
- currencyRes, pluralCount, &ptnLen, &err);
- if (U_SUCCESS(err) && ptnLen > 0) {
- UnicodeString* pattern = new UnicodeString(patternChars, ptnLen);
-#ifdef CURRENCY_PLURAL_INFO_DEBUG
- char result_1[1000];
- pattern->extract(0, pattern->length(), result_1, "UTF-8");
- std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n";
-#endif
- pattern->findAndReplace(gPart0,
- UnicodeString(numberStylePattern, numberStylePatternLen));
- pattern->findAndReplace(gPart1, gTripleCurrencySign);
-
- if (hasSeparator) {
- UnicodeString negPattern(patternChars, ptnLen);
- negPattern.findAndReplace(gPart0,
- UnicodeString(negNumberStylePattern, negNumberStylePatternLen));
- negPattern.findAndReplace(gPart1, gTripleCurrencySign);
- pattern->append(gNumberPatternSeparator);
- pattern->append(negPattern);
- }
-#ifdef CURRENCY_PLURAL_INFO_DEBUG
- pattern->extract(0, pattern->length(), result_1, "UTF-8");
- std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n";
-#endif
-
- fPluralCountToCurrencyUnitPattern->put(UnicodeString(pluralCount), pattern, status);
- }
- }
- }
- }
- delete keywords;
- ures_close(currencyRes);
- ures_close(rb);
-}
-
-
-
-void
-CurrencyPluralInfo::deleteHash(Hashtable* hTable)
-{
- if ( hTable == NULL ) {
- return;
- }
- int32_t pos = -1;
- const UHashElement* element = NULL;
- while ( (element = hTable->nextElement(pos)) != NULL ) {
- const UHashTok keyTok = element->key;
- const UHashTok valueTok = element->value;
- const UnicodeString* value = (UnicodeString*)valueTok.pointer;
- delete value;
- }
- delete hTable;
- hTable = NULL;
-}
-
-
-Hashtable*
-CurrencyPluralInfo::initHash(UErrorCode& status) {
- if ( U_FAILURE(status) ) {
- return NULL;
- }
- Hashtable* hTable;
- if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
- hTable->setValueCompartor(ValueComparator);
- return hTable;
-}
-
-
-void
-CurrencyPluralInfo::copyHash(const Hashtable* source,
- Hashtable* target,
- UErrorCode& status) {
- if ( U_FAILURE(status) ) {
- return;
- }
- int32_t pos = -1;
- const UHashElement* element = NULL;
- if ( source ) {
- while ( (element = source->nextElement(pos)) != NULL ) {
- const UHashTok keyTok = element->key;
- const UnicodeString* key = (UnicodeString*)keyTok.pointer;
- const UHashTok valueTok = element->value;
- const UnicodeString* value = (UnicodeString*)valueTok.pointer;
- UnicodeString* copy = new UnicodeString(*value);
- target->put(UnicodeString(*key), copy, status);
- if ( U_FAILURE(status) ) {
- return;
- }
- }
- }
-}
-
-
-U_NAMESPACE_END
-
-#endif
+/*
+ *******************************************************************************
+ * Copyright (C) 2009, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+
+#include "unicode/currpinf.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+//#define CURRENCY_PLURAL_INFO_DEBUG 1
+
+#ifdef CURRENCY_PLURAL_INFO_DEBUG
+#include <iostream>
+#endif
+
+
+#include "unicode/locid.h"
+#include "unicode/plurrule.h"
+#include "unicode/ures.h"
+#include "cstring.h"
+#include "hash.h"
+#include "uresimp.h"
+
+U_NAMESPACE_BEGIN
+
+
+static const UChar gNumberPatternSeparator = 0x3B; // ;
+
+U_CDECL_BEGIN
+
+/**
+ * @internal ICU 4.2
+ */
+static UBool U_CALLCONV ValueComparator(UHashTok val1, UHashTok val2);
+
+U_CDECL_END
+
+UBool
+U_CALLCONV ValueComparator(UHashTok val1, UHashTok val2) {
+ const UnicodeString* affix_1 = (UnicodeString*)val1.pointer;
+ const UnicodeString* affix_2 = (UnicodeString*)val2.pointer;
+ return *affix_1 == *affix_2;
+}
+
+
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CurrencyPluralInfo)
+
+static const UChar gDefaultCurrencyPluralPattern[] = {'0', '.', '#', '#', ' ', 0xA4, 0xA4, 0xA4, 0};
+static const UChar gTripleCurrencySign[] = {0xA4, 0xA4, 0xA4, 0};
+static const UChar gPluralCountOther[] = {0x6F, 0x74, 0x68, 0x65, 0x72, 0};
+static const UChar gPart0[] = {0x7B, 0x30, 0x7D, 0};
+static const UChar gPart1[] = {0x7B, 0x31, 0x7D, 0};
+
+static const char gNumberPatternsTag[]="NumberPatterns";
+static const char gCurrUnitPtnTag[]="CurrencyUnitPatterns";
+
+CurrencyPluralInfo::CurrencyPluralInfo(UErrorCode& status)
+: fPluralCountToCurrencyUnitPattern(NULL),
+ fPluralRules(NULL),
+ fLocale(NULL) {
+ initialize(Locale::getDefault(), status);
+}
+
+CurrencyPluralInfo::CurrencyPluralInfo(const Locale& locale, UErrorCode& status)
+: fPluralCountToCurrencyUnitPattern(NULL),
+ fPluralRules(NULL),
+ fLocale(NULL) {
+ initialize(locale, status);
+}
+
+CurrencyPluralInfo::CurrencyPluralInfo(const CurrencyPluralInfo& info)
+: UObject(info),
+ fPluralCountToCurrencyUnitPattern(NULL),
+ fPluralRules(NULL),
+ fLocale(NULL) {
+ *this = info;
+}
+
+
+CurrencyPluralInfo&
+CurrencyPluralInfo::operator=(const CurrencyPluralInfo& info) {
+ if (this == &info) {
+ return *this;
+ }
+
+ deleteHash(fPluralCountToCurrencyUnitPattern);
+ UErrorCode status = U_ZERO_ERROR;
+ fPluralCountToCurrencyUnitPattern = initHash(status);
+ copyHash(info.fPluralCountToCurrencyUnitPattern,
+ fPluralCountToCurrencyUnitPattern, status);
+ if ( U_FAILURE(status) ) {
+ return *this;
+ }
+
+ delete fPluralRules;
+ delete fLocale;
+ if (info.fPluralRules) {
+ fPluralRules = info.fPluralRules->clone();
+ } else {
+ fPluralRules = NULL;
+ }
+ if (info.fLocale) {
+ fLocale = info.fLocale->clone();
+ } else {
+ fLocale = NULL;
+ }
+ return *this;
+}
+
+
+CurrencyPluralInfo::~CurrencyPluralInfo() {
+ deleteHash(fPluralCountToCurrencyUnitPattern);
+ fPluralCountToCurrencyUnitPattern = NULL;
+ delete fPluralRules;
+ delete fLocale;
+ fPluralRules = NULL;
+ fLocale = NULL;
+}
+
+UBool
+CurrencyPluralInfo::operator==(const CurrencyPluralInfo& info) const {
+#ifdef CURRENCY_PLURAL_INFO_DEBUG
+ if (*fPluralRules == *info.fPluralRules) {
+ std::cout << "same plural rules\n";
+ }
+ if (*fLocale == *info.fLocale) {
+ std::cout << "same locale\n";
+ }
+ if (fPluralCountToCurrencyUnitPattern->equals(*info.fPluralCountToCurrencyUnitPattern)) {
+ std::cout << "same pattern\n";
+ }
+#endif
+ return *fPluralRules == *info.fPluralRules &&
+ *fLocale == *info.fLocale &&
+ fPluralCountToCurrencyUnitPattern->equals(*info.fPluralCountToCurrencyUnitPattern);
+}
+
+
+CurrencyPluralInfo*
+CurrencyPluralInfo::clone() const {
+ return new CurrencyPluralInfo(*this);
+}
+
+const PluralRules*
+CurrencyPluralInfo::getPluralRules() const {
+ return fPluralRules;
+}
+
+UnicodeString&
+CurrencyPluralInfo::getCurrencyPluralPattern(const UnicodeString& pluralCount,
+ UnicodeString& result) const {
+ const UnicodeString* currencyPluralPattern =
+ (UnicodeString*)fPluralCountToCurrencyUnitPattern->get(pluralCount);
+ if (currencyPluralPattern == NULL) {
+ // fall back to "other"
+ if (pluralCount.compare(gPluralCountOther)) {
+ currencyPluralPattern =
+ (UnicodeString*)fPluralCountToCurrencyUnitPattern->get(gPluralCountOther);
+ }
+ if (currencyPluralPattern == NULL) {
+ // no currencyUnitPatterns defined,
+ // fallback to predefined defult.
+ // This should never happen when ICU resource files are
+ // available, since currencyUnitPattern of "other" is always
+ // defined in root.
+ result = UnicodeString(gDefaultCurrencyPluralPattern);
+ return result;
+ }
+ }
+ result = *currencyPluralPattern;
+ return result;
+}
+
+const Locale&
+CurrencyPluralInfo::getLocale() const {
+ return *fLocale;
+}
+
+void
+CurrencyPluralInfo::setPluralRules(const UnicodeString& ruleDescription,
+ UErrorCode& status) {
+ if (U_SUCCESS(status)) {
+ fPluralRules = PluralRules::createRules(ruleDescription, status);
+ }
+}
+
+
+void
+CurrencyPluralInfo::setCurrencyPluralPattern(const UnicodeString& pluralCount,
+ const UnicodeString& pattern,
+ UErrorCode& status) {
+ if (U_SUCCESS(status)) {
+ fPluralCountToCurrencyUnitPattern->put(pluralCount, new UnicodeString(pattern), status);
+ }
+}
+
+
+void
+CurrencyPluralInfo::setLocale(const Locale& loc, UErrorCode& status) {
+ initialize(loc, status);
+}
+
+
+void
+CurrencyPluralInfo::initialize(const Locale& loc, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ delete fLocale;
+ fLocale = loc.clone();
+ fPluralRules = PluralRules::forLocale(loc, status);
+ setupCurrencyPluralPattern(loc, status);
+}
+
+
+void
+CurrencyPluralInfo::setupCurrencyPluralPattern(const Locale& loc, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ fPluralCountToCurrencyUnitPattern = initHash(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ UErrorCode ec = U_ZERO_ERROR;
+ UResourceBundle *rb = ures_open(NULL, loc.getName(), &ec);
+ UResourceBundle *numberPatterns = ures_getByKey(rb, gNumberPatternsTag, NULL, &ec);
+ int32_t ptnLen;
+ // TODO: 0 to be NumberFormat::fNumberStyle
+ const UChar* numberStylePattern = ures_getStringByIndex(numberPatterns, 0,
+ &ptnLen, &ec);
+ int32_t numberStylePatternLen = ptnLen;
+ const UChar* negNumberStylePattern = NULL;
+ int32_t negNumberStylePatternLen = 0;
+ // TODO: Java
+ // parse to check whether there is ";" separator in the numberStylePattern
+ UBool hasSeparator = false;
+ if (U_SUCCESS(ec)) {
+ for (int32_t styleCharIndex = 0; styleCharIndex < ptnLen; ++styleCharIndex) {
+ if (numberStylePattern[styleCharIndex] == gNumberPatternSeparator) {
+ hasSeparator = true;
+ // split the number style pattern into positive and negative
+ negNumberStylePattern = numberStylePattern + styleCharIndex + 1;
+ negNumberStylePatternLen = ptnLen - styleCharIndex - 1;
+ numberStylePatternLen = styleCharIndex;
+ }
+ }
+ }
+ ures_close(numberPatterns);
+
+ if (U_FAILURE(ec)) {
+ ures_close(rb);
+ return;
+ }
+
+ UResourceBundle *currencyRes = ures_getByKeyWithFallback(rb, gCurrUnitPtnTag, NULL, &ec);
+
+#ifdef CURRENCY_PLURAL_INFO_DEBUG
+ std::cout << "in set up\n";
+#endif
+ StringEnumeration* keywords = fPluralRules->getKeywords(ec);
+ if (U_SUCCESS(ec)) {
+ const char* pluralCount;
+ while ((pluralCount = keywords->next(NULL, ec)) != NULL) {
+ if ( U_SUCCESS(ec) ) {
+ int32_t ptnLen;
+ UErrorCode err = U_ZERO_ERROR;
+ const UChar* patternChars = ures_getStringByKeyWithFallback(
+ currencyRes, pluralCount, &ptnLen, &err);
+ if (U_SUCCESS(err) && ptnLen > 0) {
+ UnicodeString* pattern = new UnicodeString(patternChars, ptnLen);
+#ifdef CURRENCY_PLURAL_INFO_DEBUG
+ char result_1[1000];
+ pattern->extract(0, pattern->length(), result_1, "UTF-8");
+ std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n";
+#endif
+ pattern->findAndReplace(gPart0,
+ UnicodeString(numberStylePattern, numberStylePatternLen));
+ pattern->findAndReplace(gPart1, gTripleCurrencySign);
+
+ if (hasSeparator) {
+ UnicodeString negPattern(patternChars, ptnLen);
+ negPattern.findAndReplace(gPart0,
+ UnicodeString(negNumberStylePattern, negNumberStylePatternLen));
+ negPattern.findAndReplace(gPart1, gTripleCurrencySign);
+ pattern->append(gNumberPatternSeparator);
+ pattern->append(negPattern);
+ }
+#ifdef CURRENCY_PLURAL_INFO_DEBUG
+ pattern->extract(0, pattern->length(), result_1, "UTF-8");
+ std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n";
+#endif
+
+ fPluralCountToCurrencyUnitPattern->put(UnicodeString(pluralCount), pattern, status);
+ }
+ }
+ }
+ }
+ delete keywords;
+ ures_close(currencyRes);
+ ures_close(rb);
+}
+
+
+
+void
+CurrencyPluralInfo::deleteHash(Hashtable* hTable)
+{
+ if ( hTable == NULL ) {
+ return;
+ }
+ int32_t pos = -1;
+ const UHashElement* element = NULL;
+ while ( (element = hTable->nextElement(pos)) != NULL ) {
+ const UHashTok keyTok = element->key;
+ const UHashTok valueTok = element->value;
+ const UnicodeString* value = (UnicodeString*)valueTok.pointer;
+ delete value;
+ }
+ delete hTable;
+ hTable = NULL;
+}
+
+
+Hashtable*
+CurrencyPluralInfo::initHash(UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return NULL;
+ }
+ Hashtable* hTable;
+ if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ hTable->setValueCompartor(ValueComparator);
+ return hTable;
+}
+
+
+void
+CurrencyPluralInfo::copyHash(const Hashtable* source,
+ Hashtable* target,
+ UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ int32_t pos = -1;
+ const UHashElement* element = NULL;
+ if ( source ) {
+ while ( (element = source->nextElement(pos)) != NULL ) {
+ const UHashTok keyTok = element->key;
+ const UnicodeString* key = (UnicodeString*)keyTok.pointer;
+ const UHashTok valueTok = element->value;
+ const UnicodeString* value = (UnicodeString*)valueTok.pointer;
+ UnicodeString* copy = new UnicodeString(*value);
+ target->put(UnicodeString(*key), copy, status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ }
+ }
+}
+
+
+U_NAMESPACE_END
+
+#endif
Modified: trunk/source/i18n/dtitv_impl.h
===================================================================
--- trunk/source/i18n/dtitv_impl.h 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/i18n/dtitv_impl.h 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,93 +1,93 @@
-/*
-*******************************************************************************
-* Copyright (C) 2007-2008, International Business Machines Corporation and
-* others. All Rights Reserved.
-*******************************************************************************
-*
-* File DTITV_IMPL.H
-*
-*******************************************************************************
-*/
-
-
-#ifndef DTITV_IMPL_H__
-#define DTITV_IMPL_H__
-
-/**
- * \file
- * \brief C++ API: Defines macros for interval format implementation
- */
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/unistr.h"
-
-
-#define QUOTE ((UChar)0x0027)
-#define LOW_LINE ((UChar)0x005F)
-#define COLON ((UChar)0x003A)
-#define LEFT_CURLY_BRACKET ((UChar)0x007B)
-#define RIGHT_CURLY_BRACKET ((UChar)0x007D)
-#define SPACE ((UChar)0x0020)
-#define EN_DASH ((UChar)0x2013)
-
-#define DIGIT_ZERO ((UChar)0x0030)
-#define DIGIT_ONE ((UChar)0x0031)
-
-#define LOW_A ((UChar)0x0061)
-#define LOW_B ((UChar)0x0062)
-#define LOW_C ((UChar)0x0063)
-#define LOW_D ((UChar)0x0064)
-#define LOW_E ((UChar)0x0065)
-#define LOW_F ((UChar)0x0066)
-#define LOW_G ((UChar)0x0067)
-#define LOW_H ((UChar)0x0068)
-#define LOW_I ((UChar)0x0069)
-#define LOW_J ((UChar)0x006a)
-#define LOW_K ((UChar)0x006B)
-#define LOW_L ((UChar)0x006C)
-#define LOW_M ((UChar)0x006D)
-#define LOW_N ((UChar)0x006E)
-#define LOW_O ((UChar)0x006F)
-#define LOW_P ((UChar)0x0070)
-#define LOW_Q ((UChar)0x0071)
-#define LOW_R ((UChar)0x0072)
-#define LOW_S ((UChar)0x0073)
-#define LOW_T ((UChar)0x0074)
-#define LOW_U ((UChar)0x0075)
-#define LOW_V ((UChar)0x0076)
-#define LOW_W ((UChar)0x0077)
-#define LOW_Y ((UChar)0x0079)
-#define LOW_Z ((UChar)0x007A)
-
-#define CAP_A ((UChar)0x0041)
-#define CAP_C ((UChar)0x0043)
-#define CAP_D ((UChar)0x0044)
-#define CAP_E ((UChar)0x0045)
-#define CAP_F ((UChar)0x0046)
-#define CAP_G ((UChar)0x0047)
-#define CAP_H ((UChar)0x0048)
-#define CAP_K ((UChar)0x004B)
-#define CAP_L ((UChar)0x004C)
-#define CAP_M ((UChar)0x004D)
-#define CAP_O ((UChar)0x004F)
-#define CAP_Q ((UChar)0x0051)
-#define CAP_S ((UChar)0x0053)
-#define CAP_T ((UChar)0x0054)
-#define CAP_V ((UChar)0x0056)
-#define CAP_W ((UChar)0x0057)
-#define CAP_Y ((UChar)0x0059)
-#define CAP_Z ((UChar)0x005A)
-
-//#define MINIMUM_SUPPORTED_CALENDAR_FIELD UCAL_MINUTE
-
-#define MAX_E_COUNT 5
-#define MAX_M_COUNT 5
-//#define MAX_INTERVAL_INDEX 4
-#define MAX_POSITIVE_INT 56632;
-
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
-
-#endif
-//eof
+/*
+*******************************************************************************
+* Copyright (C) 2007-2008, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File DTITV_IMPL.H
+*
+*******************************************************************************
+*/
+
+
+#ifndef DTITV_IMPL_H__
+#define DTITV_IMPL_H__
+
+/**
+ * \file
+ * \brief C++ API: Defines macros for interval format implementation
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+
+
+#define QUOTE ((UChar)0x0027)
+#define LOW_LINE ((UChar)0x005F)
+#define COLON ((UChar)0x003A)
+#define LEFT_CURLY_BRACKET ((UChar)0x007B)
+#define RIGHT_CURLY_BRACKET ((UChar)0x007D)
+#define SPACE ((UChar)0x0020)
+#define EN_DASH ((UChar)0x2013)
+
+#define DIGIT_ZERO ((UChar)0x0030)
+#define DIGIT_ONE ((UChar)0x0031)
+
+#define LOW_A ((UChar)0x0061)
+#define LOW_B ((UChar)0x0062)
+#define LOW_C ((UChar)0x0063)
+#define LOW_D ((UChar)0x0064)
+#define LOW_E ((UChar)0x0065)
+#define LOW_F ((UChar)0x0066)
+#define LOW_G ((UChar)0x0067)
+#define LOW_H ((UChar)0x0068)
+#define LOW_I ((UChar)0x0069)
+#define LOW_J ((UChar)0x006a)
+#define LOW_K ((UChar)0x006B)
+#define LOW_L ((UChar)0x006C)
+#define LOW_M ((UChar)0x006D)
+#define LOW_N ((UChar)0x006E)
+#define LOW_O ((UChar)0x006F)
+#define LOW_P ((UChar)0x0070)
+#define LOW_Q ((UChar)0x0071)
+#define LOW_R ((UChar)0x0072)
+#define LOW_S ((UChar)0x0073)
+#define LOW_T ((UChar)0x0074)
+#define LOW_U ((UChar)0x0075)
+#define LOW_V ((UChar)0x0076)
+#define LOW_W ((UChar)0x0077)
+#define LOW_Y ((UChar)0x0079)
+#define LOW_Z ((UChar)0x007A)
+
+#define CAP_A ((UChar)0x0041)
+#define CAP_C ((UChar)0x0043)
+#define CAP_D ((UChar)0x0044)
+#define CAP_E ((UChar)0x0045)
+#define CAP_F ((UChar)0x0046)
+#define CAP_G ((UChar)0x0047)
+#define CAP_H ((UChar)0x0048)
+#define CAP_K ((UChar)0x004B)
+#define CAP_L ((UChar)0x004C)
+#define CAP_M ((UChar)0x004D)
+#define CAP_O ((UChar)0x004F)
+#define CAP_Q ((UChar)0x0051)
+#define CAP_S ((UChar)0x0053)
+#define CAP_T ((UChar)0x0054)
+#define CAP_V ((UChar)0x0056)
+#define CAP_W ((UChar)0x0057)
+#define CAP_Y ((UChar)0x0059)
+#define CAP_Z ((UChar)0x005A)
+
+//#define MINIMUM_SUPPORTED_CALENDAR_FIELD UCAL_MINUTE
+
+#define MAX_E_COUNT 5
+#define MAX_M_COUNT 5
+//#define MAX_INTERVAL_INDEX 4
+#define MAX_POSITIVE_INT 56632;
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
+//eof
Modified: trunk/source/i18n/dtitvfmt.cpp
===================================================================
--- trunk/source/i18n/dtitvfmt.cpp 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/i18n/dtitvfmt.cpp 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,1423 +1,1423 @@
-/*******************************************************************************
-* Copyright (C) 2008-2009, International Business Machines Corporation and
-* others. All Rights Reserved.
-*******************************************************************************
-*
-* File DTITVFMT.CPP
-*
-*******************************************************************************
-*/
-
-#include "unicode/dtitvfmt.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-//TODO: put in compilation
-//#define DTITVFMT_DEBUG 1
-
-#include "cstring.h"
-#include "unicode/msgfmt.h"
-#include "unicode/dtptngen.h"
-#include "unicode/dtitvinf.h"
-#include "unicode/calendar.h"
-#include "dtitv_impl.h"
-
-#ifdef DTITVFMT_DEBUG
-#include <iostream>
-#include "cstring.h"
-#endif
-
-#include "gregoimp.h"
-
-U_NAMESPACE_BEGIN
-
-
-
-#ifdef DTITVFMT_DEBUG
-#define PRINTMESG(msg) { std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; }
-#endif
-
-
-static const UChar gDateFormatSkeleton[][11] = {
-//yMMMMEEEEd
-{LOW_Y, CAP_M, CAP_M, CAP_M, CAP_M, CAP_E, CAP_E, CAP_E, CAP_E, LOW_D, 0},
-//yMMMMd
-{LOW_Y, CAP_M, CAP_M, CAP_M, CAP_M, LOW_D, 0},
-//yMMMd
-{LOW_Y, CAP_M, CAP_M, CAP_M, LOW_D, 0},
-//yMd
-{LOW_Y, CAP_M, LOW_D, 0} };
-
-
-static const char gDateTimePatternsTag[]="DateTimePatterns";
-
-
-// latestFirst:
-static const UChar gLaterFirstPrefix[] = {LOW_L, LOW_A, LOW_T, LOW_E, LOW_S,LOW_T, CAP_F, LOW_I, LOW_R, LOW_S, LOW_T, COLON};
-
-// earliestFirst:
-static const UChar gEarlierFirstPrefix[] = {LOW_E, LOW_A, LOW_R, LOW_L, LOW_I, LOW_E, LOW_S, LOW_T, CAP_F, LOW_I, LOW_R, LOW_S, LOW_T, COLON};
-
-
-UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalFormat)
-
-
-
-DateIntervalFormat* U_EXPORT2
-DateIntervalFormat::createInstance(const UnicodeString& skeleton,
- UErrorCode& status) {
- return createInstance(skeleton, Locale::getDefault(), status);
-}
-
-
-DateIntervalFormat* U_EXPORT2
-DateIntervalFormat::createInstance(const UnicodeString& skeleton,
- const Locale& locale,
- UErrorCode& status) {
-#ifdef DTITVFMT_DEBUG
- char result[1000];
- char result_1[1000];
- char mesg[2000];
- skeleton.extract(0, skeleton.length(), result, "UTF-8");
- UnicodeString pat;
- ((SimpleDateFormat*)dtfmt)->toPattern(pat);
- pat.extract(0, pat.length(), result_1, "UTF-8");
- sprintf(mesg, "skeleton: %s; pattern: %s\n", result, result_1);
- PRINTMESG(mesg)
-#endif
-
- DateIntervalInfo* dtitvinf = new DateIntervalInfo(locale, status);
- return create(locale, dtitvinf, &skeleton, status);
-}
-
-
-
-DateIntervalFormat* U_EXPORT2
-DateIntervalFormat::createInstance(const UnicodeString& skeleton,
- const DateIntervalInfo& dtitvinf,
- UErrorCode& status) {
- return createInstance(skeleton, Locale::getDefault(), dtitvinf, status);
-}
-
-
-DateIntervalFormat* U_EXPORT2
-DateIntervalFormat::createInstance(const UnicodeString& skeleton,
- const Locale& locale,
- const DateIntervalInfo& dtitvinf,
- UErrorCode& status) {
- DateIntervalInfo* ptn = dtitvinf.clone();
- return create(locale, ptn, &skeleton, status);
-}
-
-
-DateIntervalFormat::DateIntervalFormat()
-: fInfo(NULL),
- fDateFormat(NULL),
- fFromCalendar(NULL),
- fToCalendar(NULL),
- fDtpng(NULL)
-{}
-
-
-DateIntervalFormat::DateIntervalFormat(const DateIntervalFormat& itvfmt)
-: Format(itvfmt),
- fInfo(NULL),
- fDateFormat(NULL),
- fFromCalendar(NULL),
- fToCalendar(NULL),
- fDtpng(NULL) {
- *this = itvfmt;
-}
-
-
-DateIntervalFormat&
-DateIntervalFormat::operator=(const DateIntervalFormat& itvfmt) {
- if ( this != &itvfmt ) {
- delete fDateFormat;
- delete fInfo;
- delete fFromCalendar;
- delete fToCalendar;
- delete fDtpng;
- if ( itvfmt.fDateFormat ) {
- fDateFormat = (SimpleDateFormat*)itvfmt.fDateFormat->clone();
- } else {
- fDateFormat = NULL;
- }
- if ( itvfmt.fInfo ) {
- fInfo = itvfmt.fInfo->clone();
- } else {
- fInfo = NULL;
- }
- if ( itvfmt.fFromCalendar ) {
- fFromCalendar = itvfmt.fFromCalendar->clone();
- } else {
- fFromCalendar = NULL;
- }
- if ( itvfmt.fToCalendar ) {
- fToCalendar = itvfmt.fToCalendar->clone();
- } else {
- fToCalendar = NULL;
- }
- fSkeleton = itvfmt.fSkeleton;
- int8_t i;
- for ( i = 0; i< DateIntervalInfo::kIPI_MAX_INDEX; ++i ) {
- fIntervalPatterns[i] = itvfmt.fIntervalPatterns[i];
- }
- if (itvfmt.fDtpng) {
- fDtpng = itvfmt.fDtpng->clone();
- }
- }
- return *this;
-}
-
-
-DateIntervalFormat::~DateIntervalFormat() {
- delete fInfo;
- delete fDateFormat;
- delete fFromCalendar;
- delete fToCalendar;
- delete fDtpng;
-}
-
-
-Format*
-DateIntervalFormat::clone(void) const {
- return new DateIntervalFormat(*this);
-}
-
-
-UBool
-DateIntervalFormat::operator==(const Format& other) const {
- if ( other.getDynamicClassID() == DateIntervalFormat::getStaticClassID() ) {
- DateIntervalFormat* fmt = (DateIntervalFormat*)&other;
-#ifdef DTITVFMT_DEBUG
- UBool equal;
- equal = (this == fmt);
-
- equal = (*fInfo == *fmt->fInfo);
- equal = (*fDateFormat == *fmt->fDateFormat);
- equal = fFromCalendar->isEquivalentTo(*fmt->fFromCalendar) ;
- equal = fToCalendar->isEquivalentTo(*fmt->fToCalendar) ;
- equal = (fSkeleton == fmt->fSkeleton);
-#endif
- UBool res;
- res = ( this == fmt ) ||
- ( Format::operator==(other) &&
- fInfo &&
- ( *fInfo == *fmt->fInfo ) &&
- fDateFormat &&
- ( *fDateFormat == *fmt->fDateFormat ) &&
- fFromCalendar &&
- fFromCalendar->isEquivalentTo(*fmt->fFromCalendar) &&
- fToCalendar &&
- fToCalendar->isEquivalentTo(*fmt->fToCalendar) &&
- fSkeleton == fmt->fSkeleton &&
- fDtpng &&
- (*fDtpng == *fmt->fDtpng) );
- int8_t i;
- for (i = 0; i< DateIntervalInfo::kIPI_MAX_INDEX && res == TRUE; ++i ) {
- res = ( fIntervalPatterns[i].firstPart ==
- fmt->fIntervalPatterns[i].firstPart) &&
- ( fIntervalPatterns[i].secondPart ==
- fmt->fIntervalPatterns[i].secondPart ) &&
- ( fIntervalPatterns[i].laterDateFirst ==
- fmt->fIntervalPatterns[i].laterDateFirst) ;
- }
- return res;
- }
- return FALSE;
-}
-
-
-
-UnicodeString&
-DateIntervalFormat::format(const Formattable& obj,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition,
- UErrorCode& status) const {
- if ( U_FAILURE(status) ) {
- return appendTo;
- }
-
- if ( obj.getType() == Formattable::kObject ) {
- const UObject* formatObj = obj.getObject();
- if (formatObj->getDynamicClassID() == DateInterval::getStaticClassID()){
- return format((DateInterval*)formatObj, appendTo, fieldPosition, status);
- }
- }
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return appendTo;
-}
-
-
-UnicodeString&
-DateIntervalFormat::format(const DateInterval* dtInterval,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition,
- UErrorCode& status) const {
- if ( U_FAILURE(status) ) {
- return appendTo;
- }
-
- if ( fFromCalendar != NULL && fToCalendar != NULL &&
- fDateFormat != NULL && fInfo != NULL ) {
- fFromCalendar->setTime(dtInterval->getFromDate(), status);
- fToCalendar->setTime(dtInterval->getToDate(), status);
- if ( U_SUCCESS(status) ) {
- return format(*fFromCalendar, *fToCalendar, appendTo,fieldPosition, status);
- }
- }
- return appendTo;
-}
-
-
-UnicodeString&
-DateIntervalFormat::format(Calendar& fromCalendar,
- Calendar& toCalendar,
- UnicodeString& appendTo,
- FieldPosition& pos,
- UErrorCode& status) const {
- if ( U_FAILURE(status) ) {
- return appendTo;
- }
-
- // not support different calendar types and time zones
- //if ( fromCalendar.getType() != toCalendar.getType() ) {
- if ( !fromCalendar.isEquivalentTo(toCalendar) ||
- uprv_strcmp(fromCalendar.getType(), "gregorian") ) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return appendTo;
- }
-
- // First, find the largest different calendar field.
- UCalendarDateFields field = UCAL_FIELD_COUNT;
-
- if ( fromCalendar.get(UCAL_ERA,status) != toCalendar.get(UCAL_ERA,status)) {
- field = UCAL_ERA;
- } else if ( fromCalendar.get(UCAL_YEAR, status) !=
- toCalendar.get(UCAL_YEAR, status) ) {
- field = UCAL_YEAR;
- } else if ( fromCalendar.get(UCAL_MONTH, status) !=
- toCalendar.get(UCAL_MONTH, status) ) {
- field = UCAL_MONTH;
- } else if ( fromCalendar.get(UCAL_DATE, status) !=
- toCalendar.get(UCAL_DATE, status) ) {
- field = UCAL_DATE;
- } else if ( fromCalendar.get(UCAL_AM_PM, status) !=
- toCalendar.get(UCAL_AM_PM, status) ) {
- field = UCAL_AM_PM;
- } else if ( fromCalendar.get(UCAL_HOUR, status) !=
- toCalendar.get(UCAL_HOUR, status) ) {
- field = UCAL_HOUR;
- } else if ( fromCalendar.get(UCAL_MINUTE, status) !=
- toCalendar.get(UCAL_MINUTE, status) ) {
- field = UCAL_MINUTE;
- }
-
- if ( U_FAILURE(status) ) {
- return appendTo;
- }
- if ( field == UCAL_FIELD_COUNT ) {
- /* ignore the second/millisecond etc. small fields' difference.
- * use single date when all the above are the same.
- */
- return fDateFormat->format(fromCalendar, appendTo, pos);
- }
-
- // following call should not set wrong status,
- // all the pass-in fields are valid till here
- int32_t itvPtnIndex = DateIntervalInfo::calendarFieldToIntervalIndex(field,
- status);
- const PatternInfo& intervalPattern = fIntervalPatterns[itvPtnIndex];
-
- if ( intervalPattern.firstPart.isEmpty() &&
- intervalPattern.secondPart.isEmpty() ) {
- if ( fDateFormat->isFieldUnitIgnored(field) ) {
- /* the largest different calendar field is small than
- * the smallest calendar field in pattern,
- * return single date format.
- */
- return fDateFormat->format(fromCalendar, appendTo, pos);
- }
- return fallbackFormat(fromCalendar, toCalendar, appendTo, pos, status);
- }
- // If the first part in interval pattern is empty,
- // the 2nd part of it saves the full-pattern used in fall-back.
- // For a 'real' interval pattern, the first part will never be empty.
- if ( intervalPattern.firstPart.isEmpty() ) {
- // fall back
- UnicodeString originalPattern;
- fDateFormat->toPattern(originalPattern);
- fDateFormat->applyPattern(intervalPattern.secondPart);
- appendTo = fallbackFormat(fromCalendar, toCalendar, appendTo, pos, status);
- fDateFormat->applyPattern(originalPattern);
- return appendTo;
- }
- Calendar* firstCal;
- Calendar* secondCal;
- if ( intervalPattern.laterDateFirst ) {
- firstCal = &toCalendar;
- secondCal = &fromCalendar;
- } else {
- firstCal = &fromCalendar;
- secondCal = &toCalendar;
- }
- // break the interval pattern into 2 parts,
- // first part should not be empty,
- UnicodeString originalPattern;
- fDateFormat->toPattern(originalPattern);
- fDateFormat->applyPattern(intervalPattern.firstPart);
- fDateFormat->format(*firstCal, appendTo, pos);
- if ( !intervalPattern.secondPart.isEmpty() ) {
- fDateFormat->applyPattern(intervalPattern.secondPart);
- fDateFormat->format(*secondCal, appendTo, pos);
- }
- fDateFormat->applyPattern(originalPattern);
- return appendTo;
-}
-
-
-
-void
-DateIntervalFormat::parseObject(const UnicodeString& /* source */,
- Formattable& /* result */,
- ParsePosition& /* parse_pos */) const {
- // parseObject(const UnicodeString&, Formattable&, UErrorCode&) const
- // will set status as U_INVALID_FORMAT_ERROR if
- // parse_pos is still 0
-}
-
-
-
-
-const DateIntervalInfo*
-DateIntervalFormat::getDateIntervalInfo() const {
- return fInfo;
-}
-
-
-void
-DateIntervalFormat::setDateIntervalInfo(const DateIntervalInfo& newItvPattern,
- UErrorCode& status) {
- delete fInfo;
- fInfo = new DateIntervalInfo(newItvPattern);
- if ( fDateFormat ) {
- initializePattern(status);
- }
-}
-
-
-
-const DateFormat*
-DateIntervalFormat::getDateFormat() const {
- return fDateFormat;
-}
-
-
-DateIntervalFormat::DateIntervalFormat(const Locale& locale,
- DateIntervalInfo* dtItvInfo,
- const UnicodeString* skeleton,
- UErrorCode& status)
-: fInfo(NULL),
- fDateFormat(NULL),
- fFromCalendar(NULL),
- fToCalendar(NULL),
- fDtpng(NULL)
-{
- if ( U_FAILURE(status) ) {
- delete dtItvInfo;
- return;
- }
- fDtpng = DateTimePatternGenerator::createInstance(locale, status);
- SimpleDateFormat* dtfmt = createSDFPatternInstance(*skeleton, locale,
- fDtpng, status);
- if ( U_FAILURE(status) ) {
- delete dtItvInfo;
- delete fDtpng;
- delete dtfmt;
- return;
- }
- if ( dtfmt == NULL || dtItvInfo == NULL || fDtpng == NULL ) {
- status = U_MEMORY_ALLOCATION_ERROR;
- // safe to delete NULL
- delete dtfmt;
- delete dtItvInfo;
- delete fDtpng;
- return;
- }
- if ( skeleton ) {
- fSkeleton = *skeleton;
- }
- fInfo = dtItvInfo;
- fDateFormat = dtfmt;
- if ( dtfmt->getCalendar() ) {
- fFromCalendar = dtfmt->getCalendar()->clone();
- fToCalendar = dtfmt->getCalendar()->clone();
- } else {
- fFromCalendar = NULL;
- fToCalendar = NULL;
- }
- initializePattern(status);
-}
-
-
-SimpleDateFormat* U_EXPORT2
-DateIntervalFormat::createSDFPatternInstance(const UnicodeString& skeleton,
- const Locale& locale,
- DateTimePatternGenerator* dtpng,
- UErrorCode& status)
-{
- if ( U_FAILURE(status) ) {
- return NULL;
- }
-
- const UnicodeString pattern = dtpng->getBestPattern(skeleton, status);
- if ( U_FAILURE(status) ) {
- return NULL;
- }
- SimpleDateFormat* dtfmt = new SimpleDateFormat(pattern, locale, status);
- if ( U_FAILURE(status) ) {
- delete dtfmt;
- return NULL;
- }
- return dtfmt;
-}
-
-
-DateIntervalFormat* U_EXPORT2
-DateIntervalFormat::create(const Locale& locale,
- DateIntervalInfo* dtitvinf,
- const UnicodeString* skeleton,
- UErrorCode& status) {
- DateIntervalFormat* f = new DateIntervalFormat(locale, dtitvinf,
- skeleton, status);
- if ( f == NULL ) {
- status = U_MEMORY_ALLOCATION_ERROR;
- delete dtitvinf;
- } else if ( U_FAILURE(status) ) {
- // safe to delete f, although nothing acutally is saved
- delete f;
- f = 0;
- }
- return f;
-}
-
-
-
-/**
- * Initialize interval patterns locale to this formatter
- *
- * This code is a bit complicated since
- * 1. the interval patterns saved in resource bundle files are interval
- * patterns based on date or time only.
- * It does not have interval patterns based on both date and time.
- * Interval patterns on both date and time are algorithm generated.
- *
- * For example, it has interval patterns on skeleton "dMy" and "hm",
- * but it does not have interval patterns on skeleton "dMyhm".
- *
- * The rule to genearte interval patterns for both date and time skeleton are
- * 1) when the year, month, or day differs, concatenate the two original
- * expressions with a separator between,
- * For example, interval pattern from "Jan 10, 2007 10:10 am"
- * to "Jan 11, 2007 10:10am" is
- * "Jan 10, 2007 10:10 am - Jan 11, 2007 10:10am"
- *
- * 2) otherwise, present the date followed by the range expression
- * for the time.
- * For example, interval pattern from "Jan 10, 2007 10:10 am"
- * to "Jan 10, 2007 11:10am" is
- * "Jan 10, 2007 10:10 am - 11:10am"
- *
- * 2. even a pattern does not request a certion calendar field,
- * the interval pattern needs to include such field if such fields are
- * different between 2 dates.
- * For example, a pattern/skeleton is "hm", but the interval pattern
- * includes year, month, and date when year, month, and date differs.
- *
- * @param status output param set to success/failure code on exit
- * @stable ICU 4.0
- */
-void
-DateIntervalFormat::initializePattern(UErrorCode& status) {
- if ( U_FAILURE(status) ) {
- return;
- }
- const Locale& locale = fDateFormat->getSmpFmtLocale();
- if ( fSkeleton.isEmpty() ) {
- UnicodeString fullPattern;
- fDateFormat->toPattern(fullPattern);
-#ifdef DTITVFMT_DEBUG
- char result[1000];
- char result_1[1000];
- char mesg[2000];
- fSkeleton.extract(0, fSkeleton.length(), result, "UTF-8");
- sprintf(mesg, "in getBestSkeleton: fSkeleton: %s; \n", result);
- PRINTMESG(mesg)
-#endif
- // fSkeleton is already set by createDateIntervalInstance()
- // or by createInstance(UnicodeString skeleton, .... )
- fSkeleton = fDtpng->getSkeleton(fullPattern, status);
- if ( U_FAILURE(status) ) {
- return;
- }
- }
-
- // initialize the fIntervalPattern ordering
- int8_t i;
- for ( i = 0; i < DateIntervalInfo::kIPI_MAX_INDEX; ++i ) {
- fIntervalPatterns[i].laterDateFirst = fInfo->getDefaultOrder();
- }
-
- /* Check whether the skeleton is a combination of date and time.
- * For the complication reason 1 explained above.
- */
- UnicodeString dateSkeleton;
- UnicodeString timeSkeleton;
- UnicodeString normalizedTimeSkeleton;
- UnicodeString normalizedDateSkeleton;
-
-
- /* the difference between time skeleton and normalizedTimeSkeleton are:
- * 1. both 'H' and 'h' are normalized as 'h' in normalized time skeleton,
- * 2. 'a' is omitted in normalized time skeleton.
- * 3. there is only one appearance for 'h', 'm','v', 'z' in normalized
- * time skeleton
- *
- * The difference between date skeleton and normalizedDateSkeleton are:
- * 1. both 'y' and 'd' appear only once in normalizeDateSkeleton
- * 2. 'E' and 'EE' are normalized into 'EEE'
- * 3. 'MM' is normalized into 'M'
- */
- getDateTimeSkeleton(fSkeleton, dateSkeleton, normalizedDateSkeleton,
- timeSkeleton, normalizedTimeSkeleton);
-
-#ifdef DTITVFMT_DEBUG
- char result[1000];
- char result_1[1000];
- char mesg[2000];
- fSkeleton.extract(0, fSkeleton.length(), result, "UTF-8");
- sprintf(mesg, "in getBestSkeleton: fSkeleton: %s; \n", result);
- PRINTMESG(mesg)
-#endif
-
-
- UBool found = setSeparateDateTimePtn(normalizedDateSkeleton,
- normalizedTimeSkeleton);
-
- if ( found == false ) {
- // use fallback
- // TODO: if user asks "m"(minute), but "d"(day) differ
- if ( timeSkeleton.length() != 0 ) {
- if ( dateSkeleton.length() == 0 ) {
- // prefix with yMd
- timeSkeleton.insert(0, gDateFormatSkeleton[DateFormat::kShort]);
- UnicodeString pattern = fDtpng->getBestPattern(timeSkeleton, status);
- if ( U_FAILURE(status) ) {
- return;
- }
- // for fall back interval patterns,
- // the first part of the pattern is empty,
- // the second part of the pattern is the full-pattern
- // should be used in fall-back.
- setPatternInfo(UCAL_DATE, NULL, &pattern, fInfo->getDefaultOrder());
- setPatternInfo(UCAL_MONTH, NULL, &pattern, fInfo->getDefaultOrder());
- setPatternInfo(UCAL_YEAR, NULL, &pattern, fInfo->getDefaultOrder());
- } else {
- // TODO: fall back
- }
- } else {
- // TODO: fall back
- }
- return;
- } // end of skeleton not found
- // interval patterns for skeleton are found in resource
- if ( timeSkeleton.length() == 0 ) {
- // done
- } else if ( dateSkeleton.length() == 0 ) {
- // prefix with yMd
- timeSkeleton.insert(0, gDateFormatSkeleton[DateFormat::kShort]);
- UnicodeString pattern = fDtpng->getBestPattern(timeSkeleton, status);
- if ( U_FAILURE(status) ) {
- return;
- }
- // for fall back interval patterns,
- // the first part of the pattern is empty,
- // the second part of the pattern is the full-pattern
- // should be used in fall-back.
- setPatternInfo(UCAL_DATE, NULL, &pattern, fInfo->getDefaultOrder());
- setPatternInfo(UCAL_MONTH, NULL, &pattern, fInfo->getDefaultOrder());
- setPatternInfo(UCAL_YEAR, NULL, &pattern, fInfo->getDefaultOrder());
- } else {
- /* if both present,
- * 1) when the year, month, or day differs,
- * concatenate the two original expressions with a separator between,
- * 2) otherwise, present the date followed by the
- * range expression for the time.
- */
- /*
- * 1) when the year, month, or day differs,
- * concatenate the two original expressions with a separator between,
- */
- // if field exists, use fall back
- UnicodeString skeleton = fSkeleton;
- if ( !fieldExistsInSkeleton(UCAL_DATE, dateSkeleton) ) {
- // prefix skeleton with 'd'
- skeleton.insert(0, LOW_D);
- setFallbackPattern(UCAL_DATE, skeleton, status);
- }
- if ( !fieldExistsInSkeleton(UCAL_MONTH, dateSkeleton) ) {
- // then prefix skeleton with 'M'
- skeleton.insert(0, CAP_M);
- setFallbackPattern(UCAL_MONTH, skeleton, status);
- }
- if ( !fieldExistsInSkeleton(UCAL_YEAR, dateSkeleton) ) {
- // then prefix skeleton with 'y'
- skeleton.insert(0, LOW_Y);
- setFallbackPattern(UCAL_YEAR, skeleton, status);
- }
-
- /*
- * 2) otherwise, present the date followed by the
- * range expression for the time.
- */
- // Need the Date/Time pattern for concatnation the date with
- // the time interval.
- // The date/time pattern ( such as {0} {1} ) is saved in
- // calendar, that is why need to get the CalendarData here.
- CalendarData* calData = new CalendarData(locale, NULL, status);
-
- if ( U_FAILURE(status) ) {
- delete calData;
- return;
- }
-
- if ( calData == NULL ) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
-
- const UResourceBundle* dateTimePatternsRes = calData->getByKey(
- gDateTimePatternsTag, status);
- int32_t dateTimeFormatLength;
- const UChar* dateTimeFormat = ures_getStringByIndex(
- dateTimePatternsRes,
- (int32_t)DateFormat::kDateTime,
- &dateTimeFormatLength, &status);
- if ( U_FAILURE(status) ) {
- return;
- }
-
- UnicodeString datePattern = fDtpng->getBestPattern(dateSkeleton, status);
-
- concatSingleDate2TimeInterval(dateTimeFormat, dateTimeFormatLength,
- datePattern, UCAL_AM_PM, status);
- concatSingleDate2TimeInterval(dateTimeFormat, dateTimeFormatLength,
- datePattern, UCAL_HOUR, status);
- concatSingleDate2TimeInterval(dateTimeFormat, dateTimeFormatLength,
- datePattern, UCAL_MINUTE, status);
- delete calData;
- }
-}
-
-
-
-void U_EXPORT2
-DateIntervalFormat::getDateTimeSkeleton(const UnicodeString& skeleton,
- UnicodeString& dateSkeleton,
- UnicodeString& normalizedDateSkeleton,
- UnicodeString& timeSkeleton,
- UnicodeString& normalizedTimeSkeleton) {
- // dateSkeleton follows the sequence of y*M*E*d*
- // timeSkeleton follows the sequence of hm*[v|z]?
- int32_t ECount = 0;
- int32_t dCount = 0;
- int32_t MCount = 0;
- int32_t yCount = 0;
- int32_t hCount = 0;
- int32_t mCount = 0;
- int32_t vCount = 0;
- int32_t zCount = 0;
- int32_t i;
-
- for (i = 0; i < skeleton.length(); ++i) {
- UChar ch = skeleton[i];
- switch ( ch ) {
- case CAP_E:
- dateSkeleton.append(ch);
- ++ECount;
- break;
- case LOW_D:
- dateSkeleton.append(ch);
- ++dCount;
- break;
- case CAP_M:
- dateSkeleton.append(ch);
- ++MCount;
- break;
- case LOW_Y:
- dateSkeleton.append(ch);
- ++yCount;
- break;
- case CAP_G:
- case CAP_Y:
- case LOW_U:
- case CAP_Q:
- case LOW_Q:
- case CAP_L:
- case LOW_L:
- case CAP_W:
- case LOW_W:
- case CAP_D:
- case CAP_F:
- case LOW_G:
- case LOW_E:
- case LOW_C:
- normalizedDateSkeleton.append(ch);
- dateSkeleton.append(ch);
- break;
- case LOW_A:
- // 'a' is implicitly handled
- timeSkeleton.append(ch);
- break;
- case LOW_H:
- case CAP_H:
- timeSkeleton.append(ch);
- ++hCount;
- break;
- case LOW_M:
- timeSkeleton.append(ch);
- ++mCount;
- break;
- case LOW_Z:
- ++zCount;
- timeSkeleton.append(ch);
- break;
- case LOW_V:
- ++vCount;
- timeSkeleton.append(ch);
- break;
- case CAP_V:
- case CAP_Z:
- case LOW_K:
- case CAP_K:
- case LOW_J:
- case LOW_S:
- case CAP_S:
- case CAP_A:
- timeSkeleton.append(ch);
- normalizedTimeSkeleton.append(ch);
- break;
- }
- }
-
- /* generate normalized form for date*/
- if ( yCount != 0 ) {
- normalizedDateSkeleton.append(LOW_Y);
- }
- if ( MCount != 0 ) {
- if ( MCount < 3 ) {
- normalizedDateSkeleton.append(CAP_M);
- } else {
- int32_t i;
- for ( i = 0; i < MCount && i < MAX_M_COUNT; ++i ) {
- normalizedDateSkeleton.append(CAP_M);
- }
- }
- }
- if ( ECount != 0 ) {
- if ( ECount <= 3 ) {
- normalizedDateSkeleton.append(CAP_E);
- } else {
- int32_t i;
- for ( i = 0; i < ECount && i < MAX_E_COUNT; ++i ) {
- normalizedDateSkeleton.append(CAP_E);
- }
- }
- }
- if ( dCount != 0 ) {
- normalizedDateSkeleton.append(LOW_D);
- }
-
- /* generate normalized form for time */
- if ( hCount != 0 ) {
- normalizedTimeSkeleton.append(LOW_H);
- }
- if ( mCount != 0 ) {
- normalizedTimeSkeleton.append(LOW_M);
- }
- if ( zCount != 0 ) {
- normalizedTimeSkeleton.append(LOW_Z);
- }
- if ( vCount != 0 ) {
- normalizedTimeSkeleton.append(LOW_V);
- }
-}
-
-
-/**
- * Generate date or time interval pattern from resource,
- * and set them into the interval pattern locale to this formatter.
- *
- * It needs to handle the following:
- * 1. need to adjust field width.
- * For example, the interval patterns saved in DateIntervalInfo
- * includes "dMMMy", but not "dMMMMy".
- * Need to get interval patterns for dMMMMy from dMMMy.
- * Another example, the interval patterns saved in DateIntervalInfo
- * includes "hmv", but not "hmz".
- * Need to get interval patterns for "hmz' from 'hmv'
- *
- * 2. there might be no pattern for 'y' differ for skeleton "Md",
- * in order to get interval patterns for 'y' differ,
- * need to look for it from skeleton 'yMd'
- *
- * @param dateSkeleton normalized date skeleton
- * @param timeSkeleton normalized time skeleton
- * @return whether the resource is found for the skeleton.
- * TRUE if interval pattern found for the skeleton,
- * FALSE otherwise.
- * @stable ICU 4.0
- */
-UBool
-DateIntervalFormat::setSeparateDateTimePtn(
- const UnicodeString& dateSkeleton,
- const UnicodeString& timeSkeleton) {
- const UnicodeString* skeleton;
- // if both date and time skeleton present,
- // the final interval pattern might include time interval patterns
- // ( when, am_pm, hour, minute differ ),
- // but not date interval patterns ( when year, month, day differ ).
- // For year/month/day differ, it falls back to fall-back pattern.
- if ( timeSkeleton.length() != 0 ) {
- skeleton = &timeSkeleton;
- } else {
- skeleton = &dateSkeleton;
- }
-
- /* interval patterns for skeleton "dMMMy" (but not "dMMMMy")
- * are defined in resource,
- * interval patterns for skeleton "dMMMMy" are calculated by
- * 1. get the best match skeleton for "dMMMMy", which is "dMMMy"
- * 2. get the interval patterns for "dMMMy",
- * 3. extend "MMM" to "MMMM" in above interval patterns for "dMMMMy"
- * getBestSkeleton() is step 1.
- */
- // best skeleton, and the difference information
- int8_t differenceInfo = 0;
- const UnicodeString* bestSkeleton = fInfo->getBestSkeleton(*skeleton,
- differenceInfo);
- /* best skeleton could be NULL.
- For example: in "ca" resource file,
- interval format is defined as following
- intervalFormats{
- fallback{"{0} - {1}"}
- }
- there is no skeletons/interval patterns defined,
- and the best skeleton match could be NULL
- */
- if ( bestSkeleton == NULL ) {
- return false;
- }
-
- // difference:
- // 0 means the best matched skeleton is the same as input skeleton
- // 1 means the fields are the same, but field width are different
- // 2 means the only difference between fields are v/z,
- // -1 means there are other fields difference
- if ( differenceInfo == -1 ) {
- // skeleton has different fields, not only v/z difference
- return false;
- }
-
- if ( timeSkeleton.length() == 0 ) {
- UnicodeString extendedSkeleton;
- UnicodeString extendedBestSkeleton;
- // only has date skeleton
- setIntervalPattern(UCAL_DATE, skeleton, bestSkeleton, differenceInfo,
- &extendedSkeleton, &extendedBestSkeleton);
-
- UBool extended = setIntervalPattern(UCAL_MONTH, skeleton, bestSkeleton,
- differenceInfo,
- &extendedSkeleton, &extendedBestSkeleton);
-
- if ( extended ) {
- bestSkeleton = &extendedBestSkeleton;
- skeleton = &extendedSkeleton;
- }
- setIntervalPattern(UCAL_YEAR, skeleton, bestSkeleton, differenceInfo,
- &extendedSkeleton, &extendedBestSkeleton);
- } else {
- setIntervalPattern(UCAL_MINUTE, skeleton, bestSkeleton, differenceInfo);
- setIntervalPattern(UCAL_HOUR, skeleton, bestSkeleton, differenceInfo);
- setIntervalPattern(UCAL_AM_PM, skeleton, bestSkeleton, differenceInfo);
- }
- return true;
-}
-
-
-
-void
-DateIntervalFormat::setFallbackPattern(UCalendarDateFields field,
- const UnicodeString& skeleton,
- UErrorCode& status) {
- if ( U_FAILURE(status) ) {
- return;
- }
- UnicodeString pattern = fDtpng->getBestPattern(skeleton, status);
- if ( U_FAILURE(status) ) {
- return;
- }
- setPatternInfo(field, NULL, &pattern, fInfo->getDefaultOrder());
-}
-
-
-
-
-void
-DateIntervalFormat::setPatternInfo(UCalendarDateFields field,
- const UnicodeString* firstPart,
- const UnicodeString* secondPart,
- UBool laterDateFirst) {
- // for fall back interval patterns,
- // the first part of the pattern is empty,
- // the second part of the pattern is the full-pattern
- // should be used in fall-back.
- UErrorCode status = U_ZERO_ERROR;
- // following should not set any wrong status.
- int32_t itvPtnIndex = DateIntervalInfo::calendarFieldToIntervalIndex(field,
- status);
- if ( U_FAILURE(status) ) {
- return;
- }
- PatternInfo& ptn = fIntervalPatterns[itvPtnIndex];
- if ( firstPart ) {
- ptn.firstPart = *firstPart;
- }
- if ( secondPart ) {
- ptn.secondPart = *secondPart;
- }
- ptn.laterDateFirst = laterDateFirst;
-}
-
-void
-DateIntervalFormat::setIntervalPattern(UCalendarDateFields field,
- const UnicodeString& intervalPattern) {
- UBool order = fInfo->getDefaultOrder();
- setIntervalPattern(field, intervalPattern, order);
-}
-
-
-void
-DateIntervalFormat::setIntervalPattern(UCalendarDateFields field,
- const UnicodeString& intervalPattern,
- UBool laterDateFirst) {
- const UnicodeString* pattern = &intervalPattern;
- UBool order = laterDateFirst;
- // check for "latestFirst:" or "earliestFirst:" prefix
- int8_t prefixLength = sizeof(gLaterFirstPrefix)/sizeof(gLaterFirstPrefix[0]);
- int8_t earliestFirstLength = sizeof(gEarlierFirstPrefix)/sizeof(gEarlierFirstPrefix[0]);
- UnicodeString realPattern;
- if ( intervalPattern.startsWith(gLaterFirstPrefix, prefixLength) ) {
- order = true;
- intervalPattern.extract(prefixLength,
- intervalPattern.length() - prefixLength,
- realPattern);
- pattern = &realPattern;
- } else if ( intervalPattern.startsWith(gEarlierFirstPrefix,
- earliestFirstLength) ) {
- order = false;
- intervalPattern.extract(earliestFirstLength,
- intervalPattern.length() - earliestFirstLength,
- realPattern);
- pattern = &realPattern;
- }
-
- int32_t splitPoint = splitPatternInto2Part(*pattern);
-
- UnicodeString firstPart;
- UnicodeString secondPart;
- pattern->extract(0, splitPoint, firstPart);
- if ( splitPoint < pattern->length() ) {
- pattern->extract(splitPoint, pattern->length()-splitPoint, secondPart);
- }
- setPatternInfo(field, &firstPart, &secondPart, order);
-}
-
-
-
-
-/**
- * Generate interval pattern from existing resource
- *
- * It not only save the interval patterns,
- * but also return the extended skeleton and its best match skeleton.
- *
- * @param field largest different calendar field
- * @param skeleton skeleton
- * @param bestSkeleton the best match skeleton which has interval pattern
- * defined in resource
- * @param differenceInfo the difference between skeleton and best skeleton
- * 0 means the best matched skeleton is the same as input skeleton
- * 1 means the fields are the same, but field width are different
- * 2 means the only difference between fields are v/z,
- * -1 means there are other fields difference
- *
- * @param extendedSkeleton extended skeleton
- * @param extendedBestSkeleton extended best match skeleton
- * @return whether the interval pattern is found
- * through extending skeleton or not.
- * TRUE if interval pattern is found by
- * extending skeleton, FALSE otherwise.
- * @stable ICU 4.0
- */
-UBool
-DateIntervalFormat::setIntervalPattern(UCalendarDateFields field,
- const UnicodeString* skeleton,
- const UnicodeString* bestSkeleton,
- int8_t differenceInfo,
- UnicodeString* extendedSkeleton,
- UnicodeString* extendedBestSkeleton) {
- UErrorCode status = U_ZERO_ERROR;
- // following getIntervalPattern() should not generate error status
- UnicodeString pattern;
- fInfo->getIntervalPattern(*bestSkeleton, field, pattern, status);
- if ( pattern.isEmpty() ) {
- // single date
- if ( SimpleDateFormat::isFieldUnitIgnored(*bestSkeleton, field) ) {
- // do nothing, format will handle it
- return false;
- }
-
- // for 24 hour system, interval patterns in resource file
- // might not include pattern when am_pm differ,
- // which should be the same as hour differ.
- // add it here for simplicity
- if ( field == UCAL_AM_PM ) {
- fInfo->getIntervalPattern(*bestSkeleton, UCAL_HOUR, pattern,status);
- if ( !pattern.isEmpty() ) {
- setIntervalPattern(field, pattern);
- }
- return false;
- }
- // else, looking for pattern when 'y' differ for 'dMMMM' skeleton,
- // first, get best match pattern "MMMd",
- // since there is no pattern for 'y' differs for skeleton 'MMMd',
- // need to look for it from skeleton 'yMMMd',
- // if found, adjust field width in interval pattern from
- // "MMM" to "MMMM".
- UChar fieldLetter = fgCalendarFieldToPatternLetter[field];
- if ( extendedSkeleton ) {
- *extendedSkeleton = *skeleton;
- *extendedBestSkeleton = *bestSkeleton;
- extendedSkeleton->insert(0, fieldLetter);
- extendedBestSkeleton->insert(0, fieldLetter);
- // for example, looking for patterns when 'y' differ for
- // skeleton "MMMM".
- fInfo->getIntervalPattern(*extendedBestSkeleton,field,pattern,status);
- if ( pattern.isEmpty() && differenceInfo == 0 ) {
- // if there is no skeleton "yMMMM" defined,
- // look for the best match skeleton, for example: "yMMM"
- const UnicodeString* tmpBest = fInfo->getBestSkeleton(
- *extendedBestSkeleton, differenceInfo);
- if ( tmpBest != 0 && differenceInfo != -1 ) {
- fInfo->getIntervalPattern(*tmpBest, field, pattern, status);
- bestSkeleton = tmpBest;
- }
- }
- }
- }
- if ( !pattern.isEmpty() ) {
- if ( differenceInfo != 0 ) {
- UnicodeString adjustIntervalPattern;
- adjustFieldWidth(*skeleton, *bestSkeleton, pattern, differenceInfo,
- adjustIntervalPattern);
- setIntervalPattern(field, adjustIntervalPattern);
- } else {
- setIntervalPattern(field, pattern);
- }
- if ( extendedSkeleton && !extendedSkeleton->isEmpty() ) {
- return TRUE;
- }
- }
- return FALSE;
-}
-
-
-
-int32_t U_EXPORT2
-DateIntervalFormat::splitPatternInto2Part(const UnicodeString& intervalPattern) {
- UBool inQuote = false;
- UChar prevCh = 0;
- int32_t count = 0;
-
- /* repeatedPattern used to record whether a pattern has already seen.
- It is a pattern applies to first calendar if it is first time seen,
- otherwise, it is a pattern applies to the second calendar
- */
- UBool patternRepeated[] =
- {
- // A B C D E F G H I J K L M N O
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- // P Q R S T U V W X Y Z
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- // a b c d e f g h i j k l m n o
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- // p q r s t u v w x y z
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
-
- int8_t PATTERN_CHAR_BASE = 0x41;
-
- /* loop through the pattern string character by character looking for
- * the first repeated pattern letter, which breaks the interval pattern
- * into 2 parts.
- */
- int32_t i;
- UBool foundRepetition = false;
- for (i = 0; i < intervalPattern.length(); ++i) {
- UChar ch = intervalPattern.charAt(i);
-
- if (ch != prevCh && count > 0) {
- // check the repeativeness of pattern letter
- UBool repeated = patternRepeated[(int)(prevCh - PATTERN_CHAR_BASE)];
- if ( repeated == FALSE ) {
- patternRepeated[prevCh - PATTERN_CHAR_BASE] = TRUE;
- } else {
- foundRepetition = true;
- break;
- }
- count = 0;
- }
- if (ch == '\'') {
- // Consecutive single quotes are a single quote literal,
- // either outside of quotes or between quotes
- if ((i+1) < intervalPattern.length() &&
- intervalPattern.charAt(i+1) == '\'') {
- ++i;
- } else {
- inQuote = ! inQuote;
- }
- }
- else if (!inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/)
- || (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) {
- // ch is a date-time pattern character
- prevCh = ch;
- ++count;
- }
- }
- // check last pattern char, distinguish
- // "dd MM" ( no repetition ),
- // "d-d"(last char repeated ), and
- // "d-d MM" ( repetition found )
- if ( count > 0 && foundRepetition == FALSE ) {
- if ( patternRepeated[(int)(prevCh - PATTERN_CHAR_BASE)] == FALSE ) {
- count = 0;
- }
- }
- return (i - count);
-}
-
-
-
-UnicodeString&
-DateIntervalFormat::fallbackFormat(Calendar& fromCalendar,
- Calendar& toCalendar,
- UnicodeString& appendTo,
- FieldPosition& pos,
- UErrorCode& status) const {
- if ( U_FAILURE(status) ) {
- return appendTo;
- }
- // the fall back
- // no need delete earlierDate and laterDate since they are adopted
- UnicodeString* earlierDate = new UnicodeString();
- *earlierDate = fDateFormat->format(fromCalendar, *earlierDate, pos);
- UnicodeString* laterDate = new UnicodeString();
- *laterDate = fDateFormat->format(toCalendar, *laterDate, pos);
- UnicodeString fallbackPattern;
- fInfo->getFallbackIntervalPattern(fallbackPattern);
- Formattable fmtArray[2];
- fmtArray[0].adoptString(earlierDate);
- fmtArray[1].adoptString(laterDate);
-
- UnicodeString fallback;
- MessageFormat::format(fallbackPattern, fmtArray, 2, fallback, status);
- if ( U_SUCCESS(status) ) {
- appendTo.append(fallback);
- }
- return appendTo;
-}
-
-
-
-
-UBool U_EXPORT2
-DateIntervalFormat::fieldExistsInSkeleton(UCalendarDateFields field,
- const UnicodeString& skeleton)
-{
- const UChar fieldChar = fgCalendarFieldToPatternLetter[field];
- return ( (skeleton.indexOf(fieldChar) == -1)?FALSE:TRUE ) ;
-}
-
-
-
-void U_EXPORT2
-DateIntervalFormat::adjustFieldWidth(const UnicodeString& inputSkeleton,
- const UnicodeString& bestMatchSkeleton,
- const UnicodeString& bestIntervalPattern,
- int8_t differenceInfo,
- UnicodeString& adjustedPtn) {
- adjustedPtn = bestIntervalPattern;
- int32_t inputSkeletonFieldWidth[] =
- {
- // A B C D E F G H I J K L M N O
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- // P Q R S T U V W X Y Z
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- // a b c d e f g h i j k l m n o
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- // p q r s t u v w x y z
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
-
- int32_t bestMatchSkeletonFieldWidth[] =
- {
- // A B C D E F G H I J K L M N O
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- // P Q R S T U V W X Y Z
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- // a b c d e f g h i j k l m n o
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- // p q r s t u v w x y z
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
-
- DateIntervalInfo::parseSkeleton(inputSkeleton, inputSkeletonFieldWidth);
- DateIntervalInfo::parseSkeleton(bestMatchSkeleton, bestMatchSkeletonFieldWidth);
- if ( differenceInfo == 2 ) {
- adjustedPtn.findAndReplace("v", "z");
- }
-
- UBool inQuote = false;
- UChar prevCh = 0;
- int32_t count = 0;
-
- const int8_t PATTERN_CHAR_BASE = 0x41;
-
- // loop through the pattern string character by character
- int32_t adjustedPtnLength = adjustedPtn.length();
- int32_t i;
- for (i = 0; i < adjustedPtnLength; ++i) {
- UChar ch = adjustedPtn.charAt(i);
- if (ch != prevCh && count > 0) {
- // check the repeativeness of pattern letter
- UChar skeletonChar = prevCh;
- if ( skeletonChar == CAP_L ) {
- // there is no "L" (always be "M") in skeleton,
- // but there is "L" in pattern.
- // for skeleton "M+", the pattern might be "...L..."
- skeletonChar = CAP_M;
- }
- int32_t fieldCount = bestMatchSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)];
- int32_t inputFieldCount = inputSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)];
- if ( fieldCount == count && inputFieldCount > fieldCount ) {
- count = inputFieldCount - fieldCount;
- int32_t j;
- for ( j = 0; j < count; ++j ) {
- adjustedPtn.insert(i, prevCh);
- }
- i += count;
- adjustedPtnLength += count;
- }
- count = 0;
- }
- if (ch == '\'') {
- // Consecutive single quotes are a single quote literal,
- // either outside of quotes or between quotes
- if ((i+1) < adjustedPtn.length() && adjustedPtn.charAt(i+1) == '\'') {
- ++i;
- } else {
- inQuote = ! inQuote;
- }
- }
- else if ( ! inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/)
- || (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) {
- // ch is a date-time pattern character
- prevCh = ch;
- ++count;
- }
- }
- if ( count > 0 ) {
- // last item
- // check the repeativeness of pattern letter
- UChar skeletonChar = prevCh;
- if ( skeletonChar == CAP_L ) {
- // there is no "L" (always be "M") in skeleton,
- // but there is "L" in pattern.
- // for skeleton "M+", the pattern might be "...L..."
- skeletonChar = CAP_M;
- }
- int32_t fieldCount = bestMatchSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)];
- int32_t inputFieldCount = inputSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)];
- if ( fieldCount == count && inputFieldCount > fieldCount ) {
- count = inputFieldCount - fieldCount;
- int32_t j;
- for ( j = 0; j < count; ++j ) {
- adjustedPtn.append(prevCh);
- }
- }
- }
-}
-
-
-
-void
-DateIntervalFormat::concatSingleDate2TimeInterval(const UChar* format,
- int32_t formatLen,
- const UnicodeString& datePattern,
- UCalendarDateFields field,
- UErrorCode& status) {
- // following should not set wrong status
- int32_t itvPtnIndex = DateIntervalInfo::calendarFieldToIntervalIndex(field,
- status);
- if ( U_FAILURE(status) ) {
- return;
- }
- PatternInfo& timeItvPtnInfo = fIntervalPatterns[itvPtnIndex];
- if ( !timeItvPtnInfo.firstPart.isEmpty() ) {
- // UnicodeString allocated here is adopted, so no need to delete
- UnicodeString* timeIntervalPattern = new UnicodeString(timeItvPtnInfo.firstPart);
- timeIntervalPattern->append(timeItvPtnInfo.secondPart);
- UnicodeString* dateStr = new UnicodeString(datePattern);
- Formattable fmtArray[2];
- fmtArray[0].adoptString(timeIntervalPattern);
- fmtArray[1].adoptString(dateStr);
- UnicodeString combinedPattern;
- MessageFormat::format(UnicodeString(TRUE, format, formatLen),
- fmtArray, 2, combinedPattern, status);
- if ( U_FAILURE(status) ) {
- return;
- }
- setIntervalPattern(field, combinedPattern, timeItvPtnInfo.laterDateFirst);
- }
- // else: fall back
- // it should not happen if the interval format defined is valid
-}
-
-
-
-const UChar
-DateIntervalFormat::fgCalendarFieldToPatternLetter[] =
-{
- /*GyM*/ CAP_G, LOW_Y, CAP_M,
- /*wWd*/ LOW_W, CAP_W, LOW_D,
- /*DEF*/ CAP_D, CAP_E, CAP_F,
- /*ahH*/ LOW_A, LOW_H, CAP_H,
- /*m..*/ LOW_M,
-};
-
-
-U_NAMESPACE_END
-
-#endif
+/*******************************************************************************
+* Copyright (C) 2008-2009, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File DTITVFMT.CPP
+*
+*******************************************************************************
+*/
+
+#include "unicode/dtitvfmt.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+//TODO: put in compilation
+//#define DTITVFMT_DEBUG 1
+
+#include "cstring.h"
+#include "unicode/msgfmt.h"
+#include "unicode/dtptngen.h"
+#include "unicode/dtitvinf.h"
+#include "unicode/calendar.h"
+#include "dtitv_impl.h"
+
+#ifdef DTITVFMT_DEBUG
+#include <iostream>
+#include "cstring.h"
+#endif
+
+#include "gregoimp.h"
+
+U_NAMESPACE_BEGIN
+
+
+
+#ifdef DTITVFMT_DEBUG
+#define PRINTMESG(msg) { std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; }
+#endif
+
+
+static const UChar gDateFormatSkeleton[][11] = {
+//yMMMMEEEEd
+{LOW_Y, CAP_M, CAP_M, CAP_M, CAP_M, CAP_E, CAP_E, CAP_E, CAP_E, LOW_D, 0},
+//yMMMMd
+{LOW_Y, CAP_M, CAP_M, CAP_M, CAP_M, LOW_D, 0},
+//yMMMd
+{LOW_Y, CAP_M, CAP_M, CAP_M, LOW_D, 0},
+//yMd
+{LOW_Y, CAP_M, LOW_D, 0} };
+
+
+static const char gDateTimePatternsTag[]="DateTimePatterns";
+
+
+// latestFirst:
+static const UChar gLaterFirstPrefix[] = {LOW_L, LOW_A, LOW_T, LOW_E, LOW_S,LOW_T, CAP_F, LOW_I, LOW_R, LOW_S, LOW_T, COLON};
+
+// earliestFirst:
+static const UChar gEarlierFirstPrefix[] = {LOW_E, LOW_A, LOW_R, LOW_L, LOW_I, LOW_E, LOW_S, LOW_T, CAP_F, LOW_I, LOW_R, LOW_S, LOW_T, COLON};
+
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalFormat)
+
+
+
+DateIntervalFormat* U_EXPORT2
+DateIntervalFormat::createInstance(const UnicodeString& skeleton,
+ UErrorCode& status) {
+ return createInstance(skeleton, Locale::getDefault(), status);
+}
+
+
+DateIntervalFormat* U_EXPORT2
+DateIntervalFormat::createInstance(const UnicodeString& skeleton,
+ const Locale& locale,
+ UErrorCode& status) {
+#ifdef DTITVFMT_DEBUG
+ char result[1000];
+ char result_1[1000];
+ char mesg[2000];
+ skeleton.extract(0, skeleton.length(), result, "UTF-8");
+ UnicodeString pat;
+ ((SimpleDateFormat*)dtfmt)->toPattern(pat);
+ pat.extract(0, pat.length(), result_1, "UTF-8");
+ sprintf(mesg, "skeleton: %s; pattern: %s\n", result, result_1);
+ PRINTMESG(mesg)
+#endif
+
+ DateIntervalInfo* dtitvinf = new DateIntervalInfo(locale, status);
+ return create(locale, dtitvinf, &skeleton, status);
+}
+
+
+
+DateIntervalFormat* U_EXPORT2
+DateIntervalFormat::createInstance(const UnicodeString& skeleton,
+ const DateIntervalInfo& dtitvinf,
+ UErrorCode& status) {
+ return createInstance(skeleton, Locale::getDefault(), dtitvinf, status);
+}
+
+
+DateIntervalFormat* U_EXPORT2
+DateIntervalFormat::createInstance(const UnicodeString& skeleton,
+ const Locale& locale,
+ const DateIntervalInfo& dtitvinf,
+ UErrorCode& status) {
+ DateIntervalInfo* ptn = dtitvinf.clone();
+ return create(locale, ptn, &skeleton, status);
+}
+
+
+DateIntervalFormat::DateIntervalFormat()
+: fInfo(NULL),
+ fDateFormat(NULL),
+ fFromCalendar(NULL),
+ fToCalendar(NULL),
+ fDtpng(NULL)
+{}
+
+
+DateIntervalFormat::DateIntervalFormat(const DateIntervalFormat& itvfmt)
+: Format(itvfmt),
+ fInfo(NULL),
+ fDateFormat(NULL),
+ fFromCalendar(NULL),
+ fToCalendar(NULL),
+ fDtpng(NULL) {
+ *this = itvfmt;
+}
+
+
+DateIntervalFormat&
+DateIntervalFormat::operator=(const DateIntervalFormat& itvfmt) {
+ if ( this != &itvfmt ) {
+ delete fDateFormat;
+ delete fInfo;
+ delete fFromCalendar;
+ delete fToCalendar;
+ delete fDtpng;
+ if ( itvfmt.fDateFormat ) {
+ fDateFormat = (SimpleDateFormat*)itvfmt.fDateFormat->clone();
+ } else {
+ fDateFormat = NULL;
+ }
+ if ( itvfmt.fInfo ) {
+ fInfo = itvfmt.fInfo->clone();
+ } else {
+ fInfo = NULL;
+ }
+ if ( itvfmt.fFromCalendar ) {
+ fFromCalendar = itvfmt.fFromCalendar->clone();
+ } else {
+ fFromCalendar = NULL;
+ }
+ if ( itvfmt.fToCalendar ) {
+ fToCalendar = itvfmt.fToCalendar->clone();
+ } else {
+ fToCalendar = NULL;
+ }
+ fSkeleton = itvfmt.fSkeleton;
+ int8_t i;
+ for ( i = 0; i< DateIntervalInfo::kIPI_MAX_INDEX; ++i ) {
+ fIntervalPatterns[i] = itvfmt.fIntervalPatterns[i];
+ }
+ if (itvfmt.fDtpng) {
+ fDtpng = itvfmt.fDtpng->clone();
+ }
+ }
+ return *this;
+}
+
+
+DateIntervalFormat::~DateIntervalFormat() {
+ delete fInfo;
+ delete fDateFormat;
+ delete fFromCalendar;
+ delete fToCalendar;
+ delete fDtpng;
+}
+
+
+Format*
+DateIntervalFormat::clone(void) const {
+ return new DateIntervalFormat(*this);
+}
+
+
+UBool
+DateIntervalFormat::operator==(const Format& other) const {
+ if ( other.getDynamicClassID() == DateIntervalFormat::getStaticClassID() ) {
+ DateIntervalFormat* fmt = (DateIntervalFormat*)&other;
+#ifdef DTITVFMT_DEBUG
+ UBool equal;
+ equal = (this == fmt);
+
+ equal = (*fInfo == *fmt->fInfo);
+ equal = (*fDateFormat == *fmt->fDateFormat);
+ equal = fFromCalendar->isEquivalentTo(*fmt->fFromCalendar) ;
+ equal = fToCalendar->isEquivalentTo(*fmt->fToCalendar) ;
+ equal = (fSkeleton == fmt->fSkeleton);
+#endif
+ UBool res;
+ res = ( this == fmt ) ||
+ ( Format::operator==(other) &&
+ fInfo &&
+ ( *fInfo == *fmt->fInfo ) &&
+ fDateFormat &&
+ ( *fDateFormat == *fmt->fDateFormat ) &&
+ fFromCalendar &&
+ fFromCalendar->isEquivalentTo(*fmt->fFromCalendar) &&
+ fToCalendar &&
+ fToCalendar->isEquivalentTo(*fmt->fToCalendar) &&
+ fSkeleton == fmt->fSkeleton &&
+ fDtpng &&
+ (*fDtpng == *fmt->fDtpng) );
+ int8_t i;
+ for (i = 0; i< DateIntervalInfo::kIPI_MAX_INDEX && res == TRUE; ++i ) {
+ res = ( fIntervalPatterns[i].firstPart ==
+ fmt->fIntervalPatterns[i].firstPart) &&
+ ( fIntervalPatterns[i].secondPart ==
+ fmt->fIntervalPatterns[i].secondPart ) &&
+ ( fIntervalPatterns[i].laterDateFirst ==
+ fmt->fIntervalPatterns[i].laterDateFirst) ;
+ }
+ return res;
+ }
+ return FALSE;
+}
+
+
+
+UnicodeString&
+DateIntervalFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition,
+ UErrorCode& status) const {
+ if ( U_FAILURE(status) ) {
+ return appendTo;
+ }
+
+ if ( obj.getType() == Formattable::kObject ) {
+ const UObject* formatObj = obj.getObject();
+ if (formatObj->getDynamicClassID() == DateInterval::getStaticClassID()){
+ return format((DateInterval*)formatObj, appendTo, fieldPosition, status);
+ }
+ }
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return appendTo;
+}
+
+
+UnicodeString&
+DateIntervalFormat::format(const DateInterval* dtInterval,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition,
+ UErrorCode& status) const {
+ if ( U_FAILURE(status) ) {
+ return appendTo;
+ }
+
+ if ( fFromCalendar != NULL && fToCalendar != NULL &&
+ fDateFormat != NULL && fInfo != NULL ) {
+ fFromCalendar->setTime(dtInterval->getFromDate(), status);
+ fToCalendar->setTime(dtInterval->getToDate(), status);
+ if ( U_SUCCESS(status) ) {
+ return format(*fFromCalendar, *fToCalendar, appendTo,fieldPosition, status);
+ }
+ }
+ return appendTo;
+}
+
+
+UnicodeString&
+DateIntervalFormat::format(Calendar& fromCalendar,
+ Calendar& toCalendar,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const {
+ if ( U_FAILURE(status) ) {
+ return appendTo;
+ }
+
+ // not support different calendar types and time zones
+ //if ( fromCalendar.getType() != toCalendar.getType() ) {
+ if ( !fromCalendar.isEquivalentTo(toCalendar) ||
+ uprv_strcmp(fromCalendar.getType(), "gregorian") ) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return appendTo;
+ }
+
+ // First, find the largest different calendar field.
+ UCalendarDateFields field = UCAL_FIELD_COUNT;
+
+ if ( fromCalendar.get(UCAL_ERA,status) != toCalendar.get(UCAL_ERA,status)) {
+ field = UCAL_ERA;
+ } else if ( fromCalendar.get(UCAL_YEAR, status) !=
+ toCalendar.get(UCAL_YEAR, status) ) {
+ field = UCAL_YEAR;
+ } else if ( fromCalendar.get(UCAL_MONTH, status) !=
+ toCalendar.get(UCAL_MONTH, status) ) {
+ field = UCAL_MONTH;
+ } else if ( fromCalendar.get(UCAL_DATE, status) !=
+ toCalendar.get(UCAL_DATE, status) ) {
+ field = UCAL_DATE;
+ } else if ( fromCalendar.get(UCAL_AM_PM, status) !=
+ toCalendar.get(UCAL_AM_PM, status) ) {
+ field = UCAL_AM_PM;
+ } else if ( fromCalendar.get(UCAL_HOUR, status) !=
+ toCalendar.get(UCAL_HOUR, status) ) {
+ field = UCAL_HOUR;
+ } else if ( fromCalendar.get(UCAL_MINUTE, status) !=
+ toCalendar.get(UCAL_MINUTE, status) ) {
+ field = UCAL_MINUTE;
+ }
+
+ if ( U_FAILURE(status) ) {
+ return appendTo;
+ }
+ if ( field == UCAL_FIELD_COUNT ) {
+ /* ignore the second/millisecond etc. small fields' difference.
+ * use single date when all the above are the same.
+ */
+ return fDateFormat->format(fromCalendar, appendTo, pos);
+ }
+
+ // following call should not set wrong status,
+ // all the pass-in fields are valid till here
+ int32_t itvPtnIndex = DateIntervalInfo::calendarFieldToIntervalIndex(field,
+ status);
+ const PatternInfo& intervalPattern = fIntervalPatterns[itvPtnIndex];
+
+ if ( intervalPattern.firstPart.isEmpty() &&
+ intervalPattern.secondPart.isEmpty() ) {
+ if ( fDateFormat->isFieldUnitIgnored(field) ) {
+ /* the largest different calendar field is small than
+ * the smallest calendar field in pattern,
+ * return single date format.
+ */
+ return fDateFormat->format(fromCalendar, appendTo, pos);
+ }
+ return fallbackFormat(fromCalendar, toCalendar, appendTo, pos, status);
+ }
+ // If the first part in interval pattern is empty,
+ // the 2nd part of it saves the full-pattern used in fall-back.
+ // For a 'real' interval pattern, the first part will never be empty.
+ if ( intervalPattern.firstPart.isEmpty() ) {
+ // fall back
+ UnicodeString originalPattern;
+ fDateFormat->toPattern(originalPattern);
+ fDateFormat->applyPattern(intervalPattern.secondPart);
+ appendTo = fallbackFormat(fromCalendar, toCalendar, appendTo, pos, status);
+ fDateFormat->applyPattern(originalPattern);
+ return appendTo;
+ }
+ Calendar* firstCal;
+ Calendar* secondCal;
+ if ( intervalPattern.laterDateFirst ) {
+ firstCal = &toCalendar;
+ secondCal = &fromCalendar;
+ } else {
+ firstCal = &fromCalendar;
+ secondCal = &toCalendar;
+ }
+ // break the interval pattern into 2 parts,
+ // first part should not be empty,
+ UnicodeString originalPattern;
+ fDateFormat->toPattern(originalPattern);
+ fDateFormat->applyPattern(intervalPattern.firstPart);
+ fDateFormat->format(*firstCal, appendTo, pos);
+ if ( !intervalPattern.secondPart.isEmpty() ) {
+ fDateFormat->applyPattern(intervalPattern.secondPart);
+ fDateFormat->format(*secondCal, appendTo, pos);
+ }
+ fDateFormat->applyPattern(originalPattern);
+ return appendTo;
+}
+
+
+
+void
+DateIntervalFormat::parseObject(const UnicodeString& /* source */,
+ Formattable& /* result */,
+ ParsePosition& /* parse_pos */) const {
+ // parseObject(const UnicodeString&, Formattable&, UErrorCode&) const
+ // will set status as U_INVALID_FORMAT_ERROR if
+ // parse_pos is still 0
+}
+
+
+
+
+const DateIntervalInfo*
+DateIntervalFormat::getDateIntervalInfo() const {
+ return fInfo;
+}
+
+
+void
+DateIntervalFormat::setDateIntervalInfo(const DateIntervalInfo& newItvPattern,
+ UErrorCode& status) {
+ delete fInfo;
+ fInfo = new DateIntervalInfo(newItvPattern);
+ if ( fDateFormat ) {
+ initializePattern(status);
+ }
+}
+
+
+
+const DateFormat*
+DateIntervalFormat::getDateFormat() const {
+ return fDateFormat;
+}
+
+
+DateIntervalFormat::DateIntervalFormat(const Locale& locale,
+ DateIntervalInfo* dtItvInfo,
+ const UnicodeString* skeleton,
+ UErrorCode& status)
+: fInfo(NULL),
+ fDateFormat(NULL),
+ fFromCalendar(NULL),
+ fToCalendar(NULL),
+ fDtpng(NULL)
+{
+ if ( U_FAILURE(status) ) {
+ delete dtItvInfo;
+ return;
+ }
+ fDtpng = DateTimePatternGenerator::createInstance(locale, status);
+ SimpleDateFormat* dtfmt = createSDFPatternInstance(*skeleton, locale,
+ fDtpng, status);
+ if ( U_FAILURE(status) ) {
+ delete dtItvInfo;
+ delete fDtpng;
+ delete dtfmt;
+ return;
+ }
+ if ( dtfmt == NULL || dtItvInfo == NULL || fDtpng == NULL ) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ // safe to delete NULL
+ delete dtfmt;
+ delete dtItvInfo;
+ delete fDtpng;
+ return;
+ }
+ if ( skeleton ) {
+ fSkeleton = *skeleton;
+ }
+ fInfo = dtItvInfo;
+ fDateFormat = dtfmt;
+ if ( dtfmt->getCalendar() ) {
+ fFromCalendar = dtfmt->getCalendar()->clone();
+ fToCalendar = dtfmt->getCalendar()->clone();
+ } else {
+ fFromCalendar = NULL;
+ fToCalendar = NULL;
+ }
+ initializePattern(status);
+}
+
+
+SimpleDateFormat* U_EXPORT2
+DateIntervalFormat::createSDFPatternInstance(const UnicodeString& skeleton,
+ const Locale& locale,
+ DateTimePatternGenerator* dtpng,
+ UErrorCode& status)
+{
+ if ( U_FAILURE(status) ) {
+ return NULL;
+ }
+
+ const UnicodeString pattern = dtpng->getBestPattern(skeleton, status);
+ if ( U_FAILURE(status) ) {
+ return NULL;
+ }
+ SimpleDateFormat* dtfmt = new SimpleDateFormat(pattern, locale, status);
+ if ( U_FAILURE(status) ) {
+ delete dtfmt;
+ return NULL;
+ }
+ return dtfmt;
+}
+
+
+DateIntervalFormat* U_EXPORT2
+DateIntervalFormat::create(const Locale& locale,
+ DateIntervalInfo* dtitvinf,
+ const UnicodeString* skeleton,
+ UErrorCode& status) {
+ DateIntervalFormat* f = new DateIntervalFormat(locale, dtitvinf,
+ skeleton, status);
+ if ( f == NULL ) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ delete dtitvinf;
+ } else if ( U_FAILURE(status) ) {
+ // safe to delete f, although nothing acutally is saved
+ delete f;
+ f = 0;
+ }
+ return f;
+}
+
+
+
+/**
+ * Initialize interval patterns locale to this formatter
+ *
+ * This code is a bit complicated since
+ * 1. the interval patterns saved in resource bundle files are interval
+ * patterns based on date or time only.
+ * It does not have interval patterns based on both date and time.
+ * Interval patterns on both date and time are algorithm generated.
+ *
+ * For example, it has interval patterns on skeleton "dMy" and "hm",
+ * but it does not have interval patterns on skeleton "dMyhm".
+ *
+ * The rule to genearte interval patterns for both date and time skeleton are
+ * 1) when the year, month, or day differs, concatenate the two original
+ * expressions with a separator between,
+ * For example, interval pattern from "Jan 10, 2007 10:10 am"
+ * to "Jan 11, 2007 10:10am" is
+ * "Jan 10, 2007 10:10 am - Jan 11, 2007 10:10am"
+ *
+ * 2) otherwise, present the date followed by the range expression
+ * for the time.
+ * For example, interval pattern from "Jan 10, 2007 10:10 am"
+ * to "Jan 10, 2007 11:10am" is
+ * "Jan 10, 2007 10:10 am - 11:10am"
+ *
+ * 2. even a pattern does not request a certion calendar field,
+ * the interval pattern needs to include such field if such fields are
+ * different between 2 dates.
+ * For example, a pattern/skeleton is "hm", but the interval pattern
+ * includes year, month, and date when year, month, and date differs.
+ *
+ * @param status output param set to success/failure code on exit
+ * @stable ICU 4.0
+ */
+void
+DateIntervalFormat::initializePattern(UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ const Locale& locale = fDateFormat->getSmpFmtLocale();
+ if ( fSkeleton.isEmpty() ) {
+ UnicodeString fullPattern;
+ fDateFormat->toPattern(fullPattern);
+#ifdef DTITVFMT_DEBUG
+ char result[1000];
+ char result_1[1000];
+ char mesg[2000];
+ fSkeleton.extract(0, fSkeleton.length(), result, "UTF-8");
+ sprintf(mesg, "in getBestSkeleton: fSkeleton: %s; \n", result);
+ PRINTMESG(mesg)
+#endif
+ // fSkeleton is already set by createDateIntervalInstance()
+ // or by createInstance(UnicodeString skeleton, .... )
+ fSkeleton = fDtpng->getSkeleton(fullPattern, status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ }
+
+ // initialize the fIntervalPattern ordering
+ int8_t i;
+ for ( i = 0; i < DateIntervalInfo::kIPI_MAX_INDEX; ++i ) {
+ fIntervalPatterns[i].laterDateFirst = fInfo->getDefaultOrder();
+ }
+
+ /* Check whether the skeleton is a combination of date and time.
+ * For the complication reason 1 explained above.
+ */
+ UnicodeString dateSkeleton;
+ UnicodeString timeSkeleton;
+ UnicodeString normalizedTimeSkeleton;
+ UnicodeString normalizedDateSkeleton;
+
+
+ /* the difference between time skeleton and normalizedTimeSkeleton are:
+ * 1. both 'H' and 'h' are normalized as 'h' in normalized time skeleton,
+ * 2. 'a' is omitted in normalized time skeleton.
+ * 3. there is only one appearance for 'h', 'm','v', 'z' in normalized
+ * time skeleton
+ *
+ * The difference between date skeleton and normalizedDateSkeleton are:
+ * 1. both 'y' and 'd' appear only once in normalizeDateSkeleton
+ * 2. 'E' and 'EE' are normalized into 'EEE'
+ * 3. 'MM' is normalized into 'M'
+ */
+ getDateTimeSkeleton(fSkeleton, dateSkeleton, normalizedDateSkeleton,
+ timeSkeleton, normalizedTimeSkeleton);
+
+#ifdef DTITVFMT_DEBUG
+ char result[1000];
+ char result_1[1000];
+ char mesg[2000];
+ fSkeleton.extract(0, fSkeleton.length(), result, "UTF-8");
+ sprintf(mesg, "in getBestSkeleton: fSkeleton: %s; \n", result);
+ PRINTMESG(mesg)
+#endif
+
+
+ UBool found = setSeparateDateTimePtn(normalizedDateSkeleton,
+ normalizedTimeSkeleton);
+
+ if ( found == false ) {
+ // use fallback
+ // TODO: if user asks "m"(minute), but "d"(day) differ
+ if ( timeSkeleton.length() != 0 ) {
+ if ( dateSkeleton.length() == 0 ) {
+ // prefix with yMd
+ timeSkeleton.insert(0, gDateFormatSkeleton[DateFormat::kShort]);
+ UnicodeString pattern = fDtpng->getBestPattern(timeSkeleton, status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ // for fall back interval patterns,
+ // the first part of the pattern is empty,
+ // the second part of the pattern is the full-pattern
+ // should be used in fall-back.
+ setPatternInfo(UCAL_DATE, NULL, &pattern, fInfo->getDefaultOrder());
+ setPatternInfo(UCAL_MONTH, NULL, &pattern, fInfo->getDefaultOrder());
+ setPatternInfo(UCAL_YEAR, NULL, &pattern, fInfo->getDefaultOrder());
+ } else {
+ // TODO: fall back
+ }
+ } else {
+ // TODO: fall back
+ }
+ return;
+ } // end of skeleton not found
+ // interval patterns for skeleton are found in resource
+ if ( timeSkeleton.length() == 0 ) {
+ // done
+ } else if ( dateSkeleton.length() == 0 ) {
+ // prefix with yMd
+ timeSkeleton.insert(0, gDateFormatSkeleton[DateFormat::kShort]);
+ UnicodeString pattern = fDtpng->getBestPattern(timeSkeleton, status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ // for fall back interval patterns,
+ // the first part of the pattern is empty,
+ // the second part of the pattern is the full-pattern
+ // should be used in fall-back.
+ setPatternInfo(UCAL_DATE, NULL, &pattern, fInfo->getDefaultOrder());
+ setPatternInfo(UCAL_MONTH, NULL, &pattern, fInfo->getDefaultOrder());
+ setPatternInfo(UCAL_YEAR, NULL, &pattern, fInfo->getDefaultOrder());
+ } else {
+ /* if both present,
+ * 1) when the year, month, or day differs,
+ * concatenate the two original expressions with a separator between,
+ * 2) otherwise, present the date followed by the
+ * range expression for the time.
+ */
+ /*
+ * 1) when the year, month, or day differs,
+ * concatenate the two original expressions with a separator between,
+ */
+ // if field exists, use fall back
+ UnicodeString skeleton = fSkeleton;
+ if ( !fieldExistsInSkeleton(UCAL_DATE, dateSkeleton) ) {
+ // prefix skeleton with 'd'
+ skeleton.insert(0, LOW_D);
+ setFallbackPattern(UCAL_DATE, skeleton, status);
+ }
+ if ( !fieldExistsInSkeleton(UCAL_MONTH, dateSkeleton) ) {
+ // then prefix skeleton with 'M'
+ skeleton.insert(0, CAP_M);
+ setFallbackPattern(UCAL_MONTH, skeleton, status);
+ }
+ if ( !fieldExistsInSkeleton(UCAL_YEAR, dateSkeleton) ) {
+ // then prefix skeleton with 'y'
+ skeleton.insert(0, LOW_Y);
+ setFallbackPattern(UCAL_YEAR, skeleton, status);
+ }
+
+ /*
+ * 2) otherwise, present the date followed by the
+ * range expression for the time.
+ */
+ // Need the Date/Time pattern for concatnation the date with
+ // the time interval.
+ // The date/time pattern ( such as {0} {1} ) is saved in
+ // calendar, that is why need to get the CalendarData here.
+ CalendarData* calData = new CalendarData(locale, NULL, status);
+
+ if ( U_FAILURE(status) ) {
+ delete calData;
+ return;
+ }
+
+ if ( calData == NULL ) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ const UResourceBundle* dateTimePatternsRes = calData->getByKey(
+ gDateTimePatternsTag, status);
+ int32_t dateTimeFormatLength;
+ const UChar* dateTimeFormat = ures_getStringByIndex(
+ dateTimePatternsRes,
+ (int32_t)DateFormat::kDateTime,
+ &dateTimeFormatLength, &status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+
+ UnicodeString datePattern = fDtpng->getBestPattern(dateSkeleton, status);
+
+ concatSingleDate2TimeInterval(dateTimeFormat, dateTimeFormatLength,
+ datePattern, UCAL_AM_PM, status);
+ concatSingleDate2TimeInterval(dateTimeFormat, dateTimeFormatLength,
+ datePattern, UCAL_HOUR, status);
+ concatSingleDate2TimeInterval(dateTimeFormat, dateTimeFormatLength,
+ datePattern, UCAL_MINUTE, status);
+ delete calData;
+ }
+}
+
+
+
+void U_EXPORT2
+DateIntervalFormat::getDateTimeSkeleton(const UnicodeString& skeleton,
+ UnicodeString& dateSkeleton,
+ UnicodeString& normalizedDateSkeleton,
+ UnicodeString& timeSkeleton,
+ UnicodeString& normalizedTimeSkeleton) {
+ // dateSkeleton follows the sequence of y*M*E*d*
+ // timeSkeleton follows the sequence of hm*[v|z]?
+ int32_t ECount = 0;
+ int32_t dCount = 0;
+ int32_t MCount = 0;
+ int32_t yCount = 0;
+ int32_t hCount = 0;
+ int32_t mCount = 0;
+ int32_t vCount = 0;
+ int32_t zCount = 0;
+ int32_t i;
+
+ for (i = 0; i < skeleton.length(); ++i) {
+ UChar ch = skeleton[i];
+ switch ( ch ) {
+ case CAP_E:
+ dateSkeleton.append(ch);
+ ++ECount;
+ break;
+ case LOW_D:
+ dateSkeleton.append(ch);
+ ++dCount;
+ break;
+ case CAP_M:
+ dateSkeleton.append(ch);
+ ++MCount;
+ break;
+ case LOW_Y:
+ dateSkeleton.append(ch);
+ ++yCount;
+ break;
+ case CAP_G:
+ case CAP_Y:
+ case LOW_U:
+ case CAP_Q:
+ case LOW_Q:
+ case CAP_L:
+ case LOW_L:
+ case CAP_W:
+ case LOW_W:
+ case CAP_D:
+ case CAP_F:
+ case LOW_G:
+ case LOW_E:
+ case LOW_C:
+ normalizedDateSkeleton.append(ch);
+ dateSkeleton.append(ch);
+ break;
+ case LOW_A:
+ // 'a' is implicitly handled
+ timeSkeleton.append(ch);
+ break;
+ case LOW_H:
+ case CAP_H:
+ timeSkeleton.append(ch);
+ ++hCount;
+ break;
+ case LOW_M:
+ timeSkeleton.append(ch);
+ ++mCount;
+ break;
+ case LOW_Z:
+ ++zCount;
+ timeSkeleton.append(ch);
+ break;
+ case LOW_V:
+ ++vCount;
+ timeSkeleton.append(ch);
+ break;
+ case CAP_V:
+ case CAP_Z:
+ case LOW_K:
+ case CAP_K:
+ case LOW_J:
+ case LOW_S:
+ case CAP_S:
+ case CAP_A:
+ timeSkeleton.append(ch);
+ normalizedTimeSkeleton.append(ch);
+ break;
+ }
+ }
+
+ /* generate normalized form for date*/
+ if ( yCount != 0 ) {
+ normalizedDateSkeleton.append(LOW_Y);
+ }
+ if ( MCount != 0 ) {
+ if ( MCount < 3 ) {
+ normalizedDateSkeleton.append(CAP_M);
+ } else {
+ int32_t i;
+ for ( i = 0; i < MCount && i < MAX_M_COUNT; ++i ) {
+ normalizedDateSkeleton.append(CAP_M);
+ }
+ }
+ }
+ if ( ECount != 0 ) {
+ if ( ECount <= 3 ) {
+ normalizedDateSkeleton.append(CAP_E);
+ } else {
+ int32_t i;
+ for ( i = 0; i < ECount && i < MAX_E_COUNT; ++i ) {
+ normalizedDateSkeleton.append(CAP_E);
+ }
+ }
+ }
+ if ( dCount != 0 ) {
+ normalizedDateSkeleton.append(LOW_D);
+ }
+
+ /* generate normalized form for time */
+ if ( hCount != 0 ) {
+ normalizedTimeSkeleton.append(LOW_H);
+ }
+ if ( mCount != 0 ) {
+ normalizedTimeSkeleton.append(LOW_M);
+ }
+ if ( zCount != 0 ) {
+ normalizedTimeSkeleton.append(LOW_Z);
+ }
+ if ( vCount != 0 ) {
+ normalizedTimeSkeleton.append(LOW_V);
+ }
+}
+
+
+/**
+ * Generate date or time interval pattern from resource,
+ * and set them into the interval pattern locale to this formatter.
+ *
+ * It needs to handle the following:
+ * 1. need to adjust field width.
+ * For example, the interval patterns saved in DateIntervalInfo
+ * includes "dMMMy", but not "dMMMMy".
+ * Need to get interval patterns for dMMMMy from dMMMy.
+ * Another example, the interval patterns saved in DateIntervalInfo
+ * includes "hmv", but not "hmz".
+ * Need to get interval patterns for "hmz' from 'hmv'
+ *
+ * 2. there might be no pattern for 'y' differ for skeleton "Md",
+ * in order to get interval patterns for 'y' differ,
+ * need to look for it from skeleton 'yMd'
+ *
+ * @param dateSkeleton normalized date skeleton
+ * @param timeSkeleton normalized time skeleton
+ * @return whether the resource is found for the skeleton.
+ * TRUE if interval pattern found for the skeleton,
+ * FALSE otherwise.
+ * @stable ICU 4.0
+ */
+UBool
+DateIntervalFormat::setSeparateDateTimePtn(
+ const UnicodeString& dateSkeleton,
+ const UnicodeString& timeSkeleton) {
+ const UnicodeString* skeleton;
+ // if both date and time skeleton present,
+ // the final interval pattern might include time interval patterns
+ // ( when, am_pm, hour, minute differ ),
+ // but not date interval patterns ( when year, month, day differ ).
+ // For year/month/day differ, it falls back to fall-back pattern.
+ if ( timeSkeleton.length() != 0 ) {
+ skeleton = &timeSkeleton;
+ } else {
+ skeleton = &dateSkeleton;
+ }
+
+ /* interval patterns for skeleton "dMMMy" (but not "dMMMMy")
+ * are defined in resource,
+ * interval patterns for skeleton "dMMMMy" are calculated by
+ * 1. get the best match skeleton for "dMMMMy", which is "dMMMy"
+ * 2. get the interval patterns for "dMMMy",
+ * 3. extend "MMM" to "MMMM" in above interval patterns for "dMMMMy"
+ * getBestSkeleton() is step 1.
+ */
+ // best skeleton, and the difference information
+ int8_t differenceInfo = 0;
+ const UnicodeString* bestSkeleton = fInfo->getBestSkeleton(*skeleton,
+ differenceInfo);
+ /* best skeleton could be NULL.
+ For example: in "ca" resource file,
+ interval format is defined as following
+ intervalFormats{
+ fallback{"{0} - {1}"}
+ }
+ there is no skeletons/interval patterns defined,
+ and the best skeleton match could be NULL
+ */
+ if ( bestSkeleton == NULL ) {
+ return false;
+ }
+
+ // difference:
+ // 0 means the best matched skeleton is the same as input skeleton
+ // 1 means the fields are the same, but field width are different
+ // 2 means the only difference between fields are v/z,
+ // -1 means there are other fields difference
+ if ( differenceInfo == -1 ) {
+ // skeleton has different fields, not only v/z difference
+ return false;
+ }
+
+ if ( timeSkeleton.length() == 0 ) {
+ UnicodeString extendedSkeleton;
+ UnicodeString extendedBestSkeleton;
+ // only has date skeleton
+ setIntervalPattern(UCAL_DATE, skeleton, bestSkeleton, differenceInfo,
+ &extendedSkeleton, &extendedBestSkeleton);
+
+ UBool extended = setIntervalPattern(UCAL_MONTH, skeleton, bestSkeleton,
+ differenceInfo,
+ &extendedSkeleton, &extendedBestSkeleton);
+
+ if ( extended ) {
+ bestSkeleton = &extendedBestSkeleton;
+ skeleton = &extendedSkeleton;
+ }
+ setIntervalPattern(UCAL_YEAR, skeleton, bestSkeleton, differenceInfo,
+ &extendedSkeleton, &extendedBestSkeleton);
+ } else {
+ setIntervalPattern(UCAL_MINUTE, skeleton, bestSkeleton, differenceInfo);
+ setIntervalPattern(UCAL_HOUR, skeleton, bestSkeleton, differenceInfo);
+ setIntervalPattern(UCAL_AM_PM, skeleton, bestSkeleton, differenceInfo);
+ }
+ return true;
+}
+
+
+
+void
+DateIntervalFormat::setFallbackPattern(UCalendarDateFields field,
+ const UnicodeString& skeleton,
+ UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ UnicodeString pattern = fDtpng->getBestPattern(skeleton, status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ setPatternInfo(field, NULL, &pattern, fInfo->getDefaultOrder());
+}
+
+
+
+
+void
+DateIntervalFormat::setPatternInfo(UCalendarDateFields field,
+ const UnicodeString* firstPart,
+ const UnicodeString* secondPart,
+ UBool laterDateFirst) {
+ // for fall back interval patterns,
+ // the first part of the pattern is empty,
+ // the second part of the pattern is the full-pattern
+ // should be used in fall-back.
+ UErrorCode status = U_ZERO_ERROR;
+ // following should not set any wrong status.
+ int32_t itvPtnIndex = DateIntervalInfo::calendarFieldToIntervalIndex(field,
+ status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ PatternInfo& ptn = fIntervalPatterns[itvPtnIndex];
+ if ( firstPart ) {
+ ptn.firstPart = *firstPart;
+ }
+ if ( secondPart ) {
+ ptn.secondPart = *secondPart;
+ }
+ ptn.laterDateFirst = laterDateFirst;
+}
+
+void
+DateIntervalFormat::setIntervalPattern(UCalendarDateFields field,
+ const UnicodeString& intervalPattern) {
+ UBool order = fInfo->getDefaultOrder();
+ setIntervalPattern(field, intervalPattern, order);
+}
+
+
+void
+DateIntervalFormat::setIntervalPattern(UCalendarDateFields field,
+ const UnicodeString& intervalPattern,
+ UBool laterDateFirst) {
+ const UnicodeString* pattern = &intervalPattern;
+ UBool order = laterDateFirst;
+ // check for "latestFirst:" or "earliestFirst:" prefix
+ int8_t prefixLength = sizeof(gLaterFirstPrefix)/sizeof(gLaterFirstPrefix[0]);
+ int8_t earliestFirstLength = sizeof(gEarlierFirstPrefix)/sizeof(gEarlierFirstPrefix[0]);
+ UnicodeString realPattern;
+ if ( intervalPattern.startsWith(gLaterFirstPrefix, prefixLength) ) {
+ order = true;
+ intervalPattern.extract(prefixLength,
+ intervalPattern.length() - prefixLength,
+ realPattern);
+ pattern = &realPattern;
+ } else if ( intervalPattern.startsWith(gEarlierFirstPrefix,
+ earliestFirstLength) ) {
+ order = false;
+ intervalPattern.extract(earliestFirstLength,
+ intervalPattern.length() - earliestFirstLength,
+ realPattern);
+ pattern = &realPattern;
+ }
+
+ int32_t splitPoint = splitPatternInto2Part(*pattern);
+
+ UnicodeString firstPart;
+ UnicodeString secondPart;
+ pattern->extract(0, splitPoint, firstPart);
+ if ( splitPoint < pattern->length() ) {
+ pattern->extract(splitPoint, pattern->length()-splitPoint, secondPart);
+ }
+ setPatternInfo(field, &firstPart, &secondPart, order);
+}
+
+
+
+
+/**
+ * Generate interval pattern from existing resource
+ *
+ * It not only save the interval patterns,
+ * but also return the extended skeleton and its best match skeleton.
+ *
+ * @param field largest different calendar field
+ * @param skeleton skeleton
+ * @param bestSkeleton the best match skeleton which has interval pattern
+ * defined in resource
+ * @param differenceInfo the difference between skeleton and best skeleton
+ * 0 means the best matched skeleton is the same as input skeleton
+ * 1 means the fields are the same, but field width are different
+ * 2 means the only difference between fields are v/z,
+ * -1 means there are other fields difference
+ *
+ * @param extendedSkeleton extended skeleton
+ * @param extendedBestSkeleton extended best match skeleton
+ * @return whether the interval pattern is found
+ * through extending skeleton or not.
+ * TRUE if interval pattern is found by
+ * extending skeleton, FALSE otherwise.
+ * @stable ICU 4.0
+ */
+UBool
+DateIntervalFormat::setIntervalPattern(UCalendarDateFields field,
+ const UnicodeString* skeleton,
+ const UnicodeString* bestSkeleton,
+ int8_t differenceInfo,
+ UnicodeString* extendedSkeleton,
+ UnicodeString* extendedBestSkeleton) {
+ UErrorCode status = U_ZERO_ERROR;
+ // following getIntervalPattern() should not generate error status
+ UnicodeString pattern;
+ fInfo->getIntervalPattern(*bestSkeleton, field, pattern, status);
+ if ( pattern.isEmpty() ) {
+ // single date
+ if ( SimpleDateFormat::isFieldUnitIgnored(*bestSkeleton, field) ) {
+ // do nothing, format will handle it
+ return false;
+ }
+
+ // for 24 hour system, interval patterns in resource file
+ // might not include pattern when am_pm differ,
+ // which should be the same as hour differ.
+ // add it here for simplicity
+ if ( field == UCAL_AM_PM ) {
+ fInfo->getIntervalPattern(*bestSkeleton, UCAL_HOUR, pattern,status);
+ if ( !pattern.isEmpty() ) {
+ setIntervalPattern(field, pattern);
+ }
+ return false;
+ }
+ // else, looking for pattern when 'y' differ for 'dMMMM' skeleton,
+ // first, get best match pattern "MMMd",
+ // since there is no pattern for 'y' differs for skeleton 'MMMd',
+ // need to look for it from skeleton 'yMMMd',
+ // if found, adjust field width in interval pattern from
+ // "MMM" to "MMMM".
+ UChar fieldLetter = fgCalendarFieldToPatternLetter[field];
+ if ( extendedSkeleton ) {
+ *extendedSkeleton = *skeleton;
+ *extendedBestSkeleton = *bestSkeleton;
+ extendedSkeleton->insert(0, fieldLetter);
+ extendedBestSkeleton->insert(0, fieldLetter);
+ // for example, looking for patterns when 'y' differ for
+ // skeleton "MMMM".
+ fInfo->getIntervalPattern(*extendedBestSkeleton,field,pattern,status);
+ if ( pattern.isEmpty() && differenceInfo == 0 ) {
+ // if there is no skeleton "yMMMM" defined,
+ // look for the best match skeleton, for example: "yMMM"
+ const UnicodeString* tmpBest = fInfo->getBestSkeleton(
+ *extendedBestSkeleton, differenceInfo);
+ if ( tmpBest != 0 && differenceInfo != -1 ) {
+ fInfo->getIntervalPattern(*tmpBest, field, pattern, status);
+ bestSkeleton = tmpBest;
+ }
+ }
+ }
+ }
+ if ( !pattern.isEmpty() ) {
+ if ( differenceInfo != 0 ) {
+ UnicodeString adjustIntervalPattern;
+ adjustFieldWidth(*skeleton, *bestSkeleton, pattern, differenceInfo,
+ adjustIntervalPattern);
+ setIntervalPattern(field, adjustIntervalPattern);
+ } else {
+ setIntervalPattern(field, pattern);
+ }
+ if ( extendedSkeleton && !extendedSkeleton->isEmpty() ) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+
+int32_t U_EXPORT2
+DateIntervalFormat::splitPatternInto2Part(const UnicodeString& intervalPattern) {
+ UBool inQuote = false;
+ UChar prevCh = 0;
+ int32_t count = 0;
+
+ /* repeatedPattern used to record whether a pattern has already seen.
+ It is a pattern applies to first calendar if it is first time seen,
+ otherwise, it is a pattern applies to the second calendar
+ */
+ UBool patternRepeated[] =
+ {
+ // A B C D E F G H I J K L M N O
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // P Q R S T U V W X Y Z
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // a b c d e f g h i j k l m n o
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // p q r s t u v w x y z
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ int8_t PATTERN_CHAR_BASE = 0x41;
+
+ /* loop through the pattern string character by character looking for
+ * the first repeated pattern letter, which breaks the interval pattern
+ * into 2 parts.
+ */
+ int32_t i;
+ UBool foundRepetition = false;
+ for (i = 0; i < intervalPattern.length(); ++i) {
+ UChar ch = intervalPattern.charAt(i);
+
+ if (ch != prevCh && count > 0) {
+ // check the repeativeness of pattern letter
+ UBool repeated = patternRepeated[(int)(prevCh - PATTERN_CHAR_BASE)];
+ if ( repeated == FALSE ) {
+ patternRepeated[prevCh - PATTERN_CHAR_BASE] = TRUE;
+ } else {
+ foundRepetition = true;
+ break;
+ }
+ count = 0;
+ }
+ if (ch == '\'') {
+ // Consecutive single quotes are a single quote literal,
+ // either outside of quotes or between quotes
+ if ((i+1) < intervalPattern.length() &&
+ intervalPattern.charAt(i+1) == '\'') {
+ ++i;
+ } else {
+ inQuote = ! inQuote;
+ }
+ }
+ else if (!inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/)
+ || (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) {
+ // ch is a date-time pattern character
+ prevCh = ch;
+ ++count;
+ }
+ }
+ // check last pattern char, distinguish
+ // "dd MM" ( no repetition ),
+ // "d-d"(last char repeated ), and
+ // "d-d MM" ( repetition found )
+ if ( count > 0 && foundRepetition == FALSE ) {
+ if ( patternRepeated[(int)(prevCh - PATTERN_CHAR_BASE)] == FALSE ) {
+ count = 0;
+ }
+ }
+ return (i - count);
+}
+
+
+
+UnicodeString&
+DateIntervalFormat::fallbackFormat(Calendar& fromCalendar,
+ Calendar& toCalendar,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const {
+ if ( U_FAILURE(status) ) {
+ return appendTo;
+ }
+ // the fall back
+ // no need delete earlierDate and laterDate since they are adopted
+ UnicodeString* earlierDate = new UnicodeString();
+ *earlierDate = fDateFormat->format(fromCalendar, *earlierDate, pos);
+ UnicodeString* laterDate = new UnicodeString();
+ *laterDate = fDateFormat->format(toCalendar, *laterDate, pos);
+ UnicodeString fallbackPattern;
+ fInfo->getFallbackIntervalPattern(fallbackPattern);
+ Formattable fmtArray[2];
+ fmtArray[0].adoptString(earlierDate);
+ fmtArray[1].adoptString(laterDate);
+
+ UnicodeString fallback;
+ MessageFormat::format(fallbackPattern, fmtArray, 2, fallback, status);
+ if ( U_SUCCESS(status) ) {
+ appendTo.append(fallback);
+ }
+ return appendTo;
+}
+
+
+
+
+UBool U_EXPORT2
+DateIntervalFormat::fieldExistsInSkeleton(UCalendarDateFields field,
+ const UnicodeString& skeleton)
+{
+ const UChar fieldChar = fgCalendarFieldToPatternLetter[field];
+ return ( (skeleton.indexOf(fieldChar) == -1)?FALSE:TRUE ) ;
+}
+
+
+
+void U_EXPORT2
+DateIntervalFormat::adjustFieldWidth(const UnicodeString& inputSkeleton,
+ const UnicodeString& bestMatchSkeleton,
+ const UnicodeString& bestIntervalPattern,
+ int8_t differenceInfo,
+ UnicodeString& adjustedPtn) {
+ adjustedPtn = bestIntervalPattern;
+ int32_t inputSkeletonFieldWidth[] =
+ {
+ // A B C D E F G H I J K L M N O
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // P Q R S T U V W X Y Z
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // a b c d e f g h i j k l m n o
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // p q r s t u v w x y z
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ int32_t bestMatchSkeletonFieldWidth[] =
+ {
+ // A B C D E F G H I J K L M N O
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // P Q R S T U V W X Y Z
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // a b c d e f g h i j k l m n o
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // p q r s t u v w x y z
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ DateIntervalInfo::parseSkeleton(inputSkeleton, inputSkeletonFieldWidth);
+ DateIntervalInfo::parseSkeleton(bestMatchSkeleton, bestMatchSkeletonFieldWidth);
+ if ( differenceInfo == 2 ) {
+ adjustedPtn.findAndReplace("v", "z");
+ }
+
+ UBool inQuote = false;
+ UChar prevCh = 0;
+ int32_t count = 0;
+
+ const int8_t PATTERN_CHAR_BASE = 0x41;
+
+ // loop through the pattern string character by character
+ int32_t adjustedPtnLength = adjustedPtn.length();
+ int32_t i;
+ for (i = 0; i < adjustedPtnLength; ++i) {
+ UChar ch = adjustedPtn.charAt(i);
+ if (ch != prevCh && count > 0) {
+ // check the repeativeness of pattern letter
+ UChar skeletonChar = prevCh;
+ if ( skeletonChar == CAP_L ) {
+ // there is no "L" (always be "M") in skeleton,
+ // but there is "L" in pattern.
+ // for skeleton "M+", the pattern might be "...L..."
+ skeletonChar = CAP_M;
+ }
+ int32_t fieldCount = bestMatchSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)];
+ int32_t inputFieldCount = inputSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)];
+ if ( fieldCount == count && inputFieldCount > fieldCount ) {
+ count = inputFieldCount - fieldCount;
+ int32_t j;
+ for ( j = 0; j < count; ++j ) {
+ adjustedPtn.insert(i, prevCh);
+ }
+ i += count;
+ adjustedPtnLength += count;
+ }
+ count = 0;
+ }
+ if (ch == '\'') {
+ // Consecutive single quotes are a single quote literal,
+ // either outside of quotes or between quotes
+ if ((i+1) < adjustedPtn.length() && adjustedPtn.charAt(i+1) == '\'') {
+ ++i;
+ } else {
+ inQuote = ! inQuote;
+ }
+ }
+ else if ( ! inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/)
+ || (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) {
+ // ch is a date-time pattern character
+ prevCh = ch;
+ ++count;
+ }
+ }
+ if ( count > 0 ) {
+ // last item
+ // check the repeativeness of pattern letter
+ UChar skeletonChar = prevCh;
+ if ( skeletonChar == CAP_L ) {
+ // there is no "L" (always be "M") in skeleton,
+ // but there is "L" in pattern.
+ // for skeleton "M+", the pattern might be "...L..."
+ skeletonChar = CAP_M;
+ }
+ int32_t fieldCount = bestMatchSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)];
+ int32_t inputFieldCount = inputSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)];
+ if ( fieldCount == count && inputFieldCount > fieldCount ) {
+ count = inputFieldCount - fieldCount;
+ int32_t j;
+ for ( j = 0; j < count; ++j ) {
+ adjustedPtn.append(prevCh);
+ }
+ }
+ }
+}
+
+
+
+void
+DateIntervalFormat::concatSingleDate2TimeInterval(const UChar* format,
+ int32_t formatLen,
+ const UnicodeString& datePattern,
+ UCalendarDateFields field,
+ UErrorCode& status) {
+ // following should not set wrong status
+ int32_t itvPtnIndex = DateIntervalInfo::calendarFieldToIntervalIndex(field,
+ status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ PatternInfo& timeItvPtnInfo = fIntervalPatterns[itvPtnIndex];
+ if ( !timeItvPtnInfo.firstPart.isEmpty() ) {
+ // UnicodeString allocated here is adopted, so no need to delete
+ UnicodeString* timeIntervalPattern = new UnicodeString(timeItvPtnInfo.firstPart);
+ timeIntervalPattern->append(timeItvPtnInfo.secondPart);
+ UnicodeString* dateStr = new UnicodeString(datePattern);
+ Formattable fmtArray[2];
+ fmtArray[0].adoptString(timeIntervalPattern);
+ fmtArray[1].adoptString(dateStr);
+ UnicodeString combinedPattern;
+ MessageFormat::format(UnicodeString(TRUE, format, formatLen),
+ fmtArray, 2, combinedPattern, status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ setIntervalPattern(field, combinedPattern, timeItvPtnInfo.laterDateFirst);
+ }
+ // else: fall back
+ // it should not happen if the interval format defined is valid
+}
+
+
+
+const UChar
+DateIntervalFormat::fgCalendarFieldToPatternLetter[] =
+{
+ /*GyM*/ CAP_G, LOW_Y, CAP_M,
+ /*wWd*/ LOW_W, CAP_W, LOW_D,
+ /*DEF*/ CAP_D, CAP_E, CAP_F,
+ /*ahH*/ LOW_A, LOW_H, CAP_H,
+ /*m..*/ LOW_M,
+};
+
+
+U_NAMESPACE_END
+
+#endif
Modified: trunk/source/i18n/dtitvinf.cpp
===================================================================
--- trunk/source/i18n/dtitvinf.cpp 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/i18n/dtitvinf.cpp 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,642 +1,642 @@
-/*******************************************************************************
-* Copyright (C) 2008-2009, International Business Machines Corporation and
-* others. All Rights Reserved.
-*******************************************************************************
-*
-* File DTITVINF.CPP
-*
-*******************************************************************************
-*/
-
-#include "unicode/dtitvinf.h"
-
-
-#if !UCONFIG_NO_FORMATTING
-
-//TODO: define it in compiler time
-//#define DTITVINF_DEBUG 1
-
-
-#ifdef DTITVINF_DEBUG
-#include <iostream>
-#endif
-
-#include "cstring.h"
-#include "unicode/msgfmt.h"
-#include "dtitv_impl.h"
-#include "hash.h"
-#include "gregoimp.h"
-#include "uresimp.h"
-#include "hash.h"
-#include "gregoimp.h"
-#include "uresimp.h"
-
-
-U_NAMESPACE_BEGIN
-
-
-#ifdef DTITVINF_DEBUG
-#define PRINTMESG(msg) { std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; }
-#endif
-
-UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalInfo)
-
-static const char gCalendarTag[]="calendar";
-static const char gGregorianTag[]="gregorian";
-static const char gIntervalDateTimePatternTag[]="intervalFormats";
-static const char gFallbackPatternTag[]="fallback";
-
-// {0}
-static const UChar gFirstPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET};
-// {1}
-static const UChar gSecondPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ONE, RIGHT_CURLY_BRACKET};
-
-// default fall-back
-static const UChar gDefaultFallbackPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, EN_DASH, SPACE, LEFT_CURLY_BRACKET, DIGIT_ONE, RIGHT_CURLY_BRACKET, 0};
-
-
-
-DateIntervalInfo::DateIntervalInfo(UErrorCode& status)
-: fFallbackIntervalPattern(gDefaultFallbackPattern),
- fFirstDateInPtnIsLaterDate(false),
- fIntervalPatterns(NULL)
-{
- fIntervalPatterns = initHash(status);
-}
-
-
-
-DateIntervalInfo::DateIntervalInfo(const Locale& locale, UErrorCode& status)
-: fFallbackIntervalPattern(gDefaultFallbackPattern),
- fFirstDateInPtnIsLaterDate(false),
- fIntervalPatterns(NULL)
-{
- initializeData(locale, status);
-}
-
-
-
-void
-DateIntervalInfo::setIntervalPattern(const UnicodeString& skeleton,
- UCalendarDateFields lrgDiffCalUnit,
- const UnicodeString& intervalPattern,
- UErrorCode& status) {
-
- if ( lrgDiffCalUnit == UCAL_HOUR_OF_DAY ) {
- setIntervalPatternInternally(skeleton, UCAL_AM_PM, intervalPattern, status);
- setIntervalPatternInternally(skeleton, UCAL_HOUR, intervalPattern, status);
- } else if ( lrgDiffCalUnit == UCAL_DAY_OF_MONTH ||
- lrgDiffCalUnit == UCAL_DAY_OF_WEEK ) {
- setIntervalPatternInternally(skeleton, UCAL_DATE, intervalPattern, status);
- } else {
- setIntervalPatternInternally(skeleton, lrgDiffCalUnit, intervalPattern, status);
- }
-}
-
-
-void
-DateIntervalInfo::setFallbackIntervalPattern(
- const UnicodeString& fallbackPattern,
- UErrorCode& status) {
- if ( U_FAILURE(status) ) {
- return;
- }
- int32_t firstPatternIndex = fallbackPattern.indexOf(gFirstPattern,
- sizeof(gFirstPattern)/sizeof(gFirstPattern[0]), 0);
- int32_t secondPatternIndex = fallbackPattern.indexOf(gSecondPattern,
- sizeof(gSecondPattern)/sizeof(gSecondPattern[0]), 0);
- if ( firstPatternIndex == -1 || secondPatternIndex == -1 ) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return;
- }
- if ( firstPatternIndex > secondPatternIndex ) {
- fFirstDateInPtnIsLaterDate = true;
- }
- fFallbackIntervalPattern = fallbackPattern;
-}
-
-
-
-DateIntervalInfo::DateIntervalInfo(const DateIntervalInfo& dtitvinf)
-: UObject(dtitvinf),
- fIntervalPatterns(NULL)
-{
- *this = dtitvinf;
-}
-
-
-
-DateIntervalInfo&
-DateIntervalInfo::operator=(const DateIntervalInfo& dtitvinf) {
- if ( this == &dtitvinf ) {
- return *this;
- }
-
- UErrorCode status = U_ZERO_ERROR;
- deleteHash(fIntervalPatterns);
- fIntervalPatterns = initHash(status);
- copyHash(dtitvinf.fIntervalPatterns, fIntervalPatterns, status);
- if ( U_FAILURE(status) ) {
- return *this;
- }
-
- fFallbackIntervalPattern = dtitvinf.fFallbackIntervalPattern;
- fFirstDateInPtnIsLaterDate = dtitvinf.fFirstDateInPtnIsLaterDate;
- return *this;
-}
-
-
-DateIntervalInfo*
-DateIntervalInfo::clone() const {
- return new DateIntervalInfo(*this);
-}
-
-
-DateIntervalInfo::~DateIntervalInfo() {
- deleteHash(fIntervalPatterns);
- fIntervalPatterns = NULL;
-}
-
-
-UBool
-DateIntervalInfo::operator==(const DateIntervalInfo& other) const {
- UBool equal = (
- fFallbackIntervalPattern == other.fFallbackIntervalPattern &&
- fFirstDateInPtnIsLaterDate == other.fFirstDateInPtnIsLaterDate );
-
- if ( equal == TRUE ) {
- equal = fIntervalPatterns->equals(*(other.fIntervalPatterns));
- }
-
- return equal;
-}
-
-
-UnicodeString&
-DateIntervalInfo::getIntervalPattern(const UnicodeString& skeleton,
- UCalendarDateFields field,
- UnicodeString& result,
- UErrorCode& status) const {
- if ( U_FAILURE(status) ) {
- return result;
- }
-
- const UnicodeString* patternsOfOneSkeleton = (UnicodeString*) fIntervalPatterns->get(skeleton);
- if ( patternsOfOneSkeleton != NULL ) {
- IntervalPatternIndex index = calendarFieldToIntervalIndex(field, status);
- if ( U_FAILURE(status) ) {
- return result;
- }
- const UnicodeString& intervalPattern = patternsOfOneSkeleton[index];
- if ( !intervalPattern.isEmpty() ) {
- result = intervalPattern;
- }
- }
- return result;
-}
-
-
-UBool
-DateIntervalInfo::getDefaultOrder() const {
- return fFirstDateInPtnIsLaterDate;
-}
-
-
-UnicodeString&
-DateIntervalInfo::getFallbackIntervalPattern(UnicodeString& result) const {
- result = fFallbackIntervalPattern;
- return result;
-}
-
-
-void
-DateIntervalInfo::initializeData(const Locale& locale, UErrorCode& err)
-{
- fIntervalPatterns = initHash(err);
- if ( U_FAILURE(err) ) {
- return;
- }
- const char *locName = locale.getName();
- char parentLocale[ULOC_FULLNAME_CAPACITY];
- int32_t locNameLen;
- uprv_strcpy(parentLocale, locName);
- UErrorCode status = U_ZERO_ERROR;
- Hashtable skeletonSet(TRUE, status);
- if ( U_FAILURE(status) ) {
- return;
- }
- do {
- UResourceBundle *rb, *calBundle, *gregorianBundle, *itvDtPtnResource;
- rb = ures_open(NULL, parentLocale, &status);
- calBundle = ures_getByKey(rb, gCalendarTag, NULL, &status);
- gregorianBundle = ures_getByKey(calBundle, gGregorianTag, NULL, &status);
- itvDtPtnResource = ures_getByKeyWithFallback(gregorianBundle,
- gIntervalDateTimePatternTag, NULL, &status);
-
- if ( U_SUCCESS(status) ) {
- // look for fallback first, since it establishes the default order
- const UChar* resStr;
- int32_t resStrLen = 0;
- resStr = ures_getStringByKeyWithFallback(itvDtPtnResource,
- gFallbackPatternTag,
- &resStrLen, &status);
- if ( U_SUCCESS(status) ) {
- UnicodeString pattern = UnicodeString(TRUE, resStr, resStrLen);
- setFallbackIntervalPattern(pattern, status);
- }
-
- int32_t size = ures_getSize(itvDtPtnResource);
- int32_t index;
- for ( index = 0; index < size; ++index ) {
- UResourceBundle* oneRes = ures_getByIndex(itvDtPtnResource, index,
- NULL, &status);
- if ( U_SUCCESS(status) ) {
- const char* skeleton = ures_getKey(oneRes);
- if ( skeleton == NULL ||
- skeletonSet.geti(UnicodeString(skeleton)) == 1 ) {
- ures_close(oneRes);
- continue;
- }
- skeletonSet.puti(UnicodeString(skeleton), 1, status);
- if ( uprv_strcmp(skeleton, gFallbackPatternTag) == 0 ) {
- ures_close(oneRes);
- continue; // fallback
- }
-
- UResourceBundle* intervalPatterns = ures_getByKey(
- itvDtPtnResource, skeleton, NULL, &status);
-
- if ( U_FAILURE(status) ) {
- ures_close(intervalPatterns);
- ures_close(oneRes);
- break;
- }
- if ( intervalPatterns == NULL ) {
- ures_close(intervalPatterns);
- ures_close(oneRes);
- continue;
- }
-
- const UChar* pattern;
- const char* key;
- int32_t ptLength;
- int32_t ptnNum = ures_getSize(intervalPatterns);
- int32_t ptnIndex;
- for ( ptnIndex = 0; ptnIndex < ptnNum; ++ptnIndex ) {
- pattern = ures_getNextString(intervalPatterns, &ptLength, &key,
- &status);
- if ( U_FAILURE(status) ) {
- break;
- }
-
- UCalendarDateFields calendarField = UCAL_FIELD_COUNT;
- if ( !uprv_strcmp(key, "y") ) {
- calendarField = UCAL_YEAR;
- } else if ( !uprv_strcmp(key, "M") ) {
- calendarField = UCAL_MONTH;
- } else if ( !uprv_strcmp(key, "d") ) {
- calendarField = UCAL_DATE;
- } else if ( !uprv_strcmp(key, "a") ) {
- calendarField = UCAL_AM_PM;
- } else if ( !uprv_strcmp(key, "h") ) {
- calendarField = UCAL_HOUR;
- } else if ( !uprv_strcmp(key, "m") ) {
- calendarField = UCAL_MINUTE;
- }
- if ( calendarField != UCAL_FIELD_COUNT ) {
- setIntervalPatternInternally(skeleton, calendarField, pattern,status);
- }
- }
- ures_close(intervalPatterns);
- }
- ures_close(oneRes);
- }
- }
- ures_close(itvDtPtnResource);
- ures_close(gregorianBundle);
- ures_close(calBundle);
- ures_close(rb);
- status = U_ZERO_ERROR;
- locNameLen = uloc_getParent(parentLocale, parentLocale,
- ULOC_FULLNAME_CAPACITY,&status);
- } while ( locNameLen > 0 );
-}
-
-
-
-void
-DateIntervalInfo::setIntervalPatternInternally(const UnicodeString& skeleton,
- UCalendarDateFields lrgDiffCalUnit,
- const UnicodeString& intervalPattern,
- UErrorCode& status) {
- IntervalPatternIndex index = calendarFieldToIntervalIndex(lrgDiffCalUnit,status);
- if ( U_FAILURE(status) ) {
- return;
- }
- UnicodeString* patternsOfOneSkeleton = (UnicodeString*)(fIntervalPatterns->get(skeleton));
- UBool emptyHash = false;
- if ( patternsOfOneSkeleton == NULL ) {
- patternsOfOneSkeleton = new UnicodeString[kIPI_MAX_INDEX];
- emptyHash = true;
- }
-
- patternsOfOneSkeleton[index] = intervalPattern;
- if ( emptyHash == TRUE ) {
- fIntervalPatterns->put(skeleton, patternsOfOneSkeleton, status);
- }
-}
-
-
-
-void
-DateIntervalInfo::parseSkeleton(const UnicodeString& skeleton,
- int32_t* skeletonFieldWidth) {
- const int8_t PATTERN_CHAR_BASE = 0x41;
- int32_t i;
- for ( i = 0; i < skeleton.length(); ++i ) {
- // it is an ASCII char in skeleton
- int8_t ch = (int8_t)skeleton.charAt(i);
- ++skeletonFieldWidth[ch - PATTERN_CHAR_BASE];
- }
-}
-
-
-
-UBool
-DateIntervalInfo::stringNumeric(int32_t fieldWidth, int32_t anotherFieldWidth,
- char patternLetter) {
- if ( patternLetter == 'M' ) {
- if ( fieldWidth <= 2 && anotherFieldWidth > 2 ||
- fieldWidth > 2 && anotherFieldWidth <= 2 ) {
- return true;
- }
- }
- return false;
-}
-
-
-
-const UnicodeString*
-DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton,
- int8_t& bestMatchDistanceInfo) const {
-#ifdef DTITVINF_DEBUG
- char result[1000];
- char result_1[1000];
- char mesg[2000];
- skeleton.extract(0, skeleton.length(), result, "UTF-8");
- sprintf(mesg, "in getBestSkeleton: skeleton: %s; \n", result);
- PRINTMESG(mesg)
-#endif
-
-
- int32_t inputSkeletonFieldWidth[] =
- {
- // A B C D E F G H I J K L M N O
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- // P Q R S T U V W X Y Z
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- // a b c d e f g h i j k l m n o
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- // p q r s t u v w x y z
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
-
- int32_t skeletonFieldWidth[] =
- {
- // A B C D E F G H I J K L M N O
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- // P Q R S T U V W X Y Z
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- // a b c d e f g h i j k l m n o
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- // p q r s t u v w x y z
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
-
- const int32_t DIFFERENT_FIELD = 0x1000;
- const int32_t STRING_NUMERIC_DIFFERENCE = 0x100;
- const int32_t BASE = 0x41;
- const UChar CHAR_V = 0x0076;
- const UChar CHAR_Z = 0x007A;
-
- // hack for 'v' and 'z'.
- // resource bundle only have time skeletons ending with 'v',
- // but not for time skeletons ending with 'z'.
- UBool replaceZWithV = false;
- const UnicodeString* inputSkeleton = &skeleton;
- UnicodeString copySkeleton;
- if ( skeleton.indexOf(CHAR_Z) != -1 ) {
- UChar zstr[2];
- UChar vstr[2];
- zstr[0]=CHAR_Z;
- vstr[0]=CHAR_V;
- zstr[1]=0;
- vstr[1]=0;
- copySkeleton = skeleton;
- copySkeleton.findAndReplace(zstr, vstr);
- inputSkeleton = ©Skeleton;
- replaceZWithV = true;
- }
-
- parseSkeleton(*inputSkeleton, inputSkeletonFieldWidth);
- int32_t bestDistance = MAX_POSITIVE_INT;
- const UnicodeString* bestSkeleton = NULL;
-
- // 0 means exact the same skeletons;
- // 1 means having the same field, but with different length,
- // 2 means only z/v differs
- // -1 means having different field.
- bestMatchDistanceInfo = 0;
- int8_t fieldLength = sizeof(skeletonFieldWidth)/sizeof(skeletonFieldWidth[0]);
-
- int32_t pos = -1;
- const UHashElement* elem = NULL;
- while ( (elem = fIntervalPatterns->nextElement(pos)) != NULL ) {
- const UHashTok keyTok = elem->key;
- UnicodeString* skeleton = (UnicodeString*)keyTok.pointer;
-#ifdef DTITVINF_DEBUG
- skeleton->extract(0, skeleton->length(), result, "UTF-8");
- sprintf(mesg, "available skeletons: skeleton: %s; \n", result);
- PRINTMESG(mesg)
-#endif
-
- // clear skeleton field width
- int8_t i;
- for ( i = 0; i < fieldLength; ++i ) {
- skeletonFieldWidth[i] = 0;
- }
- parseSkeleton(*skeleton, skeletonFieldWidth);
- // calculate distance
- int32_t distance = 0;
- int8_t fieldDifference = 1;
- for ( i = 0; i < fieldLength; ++i ) {
- int32_t inputFieldWidth = inputSkeletonFieldWidth[i];
- int32_t fieldWidth = skeletonFieldWidth[i];
- if ( inputFieldWidth == fieldWidth ) {
- continue;
- }
- if ( inputFieldWidth == 0 ) {
- fieldDifference = -1;
- distance += DIFFERENT_FIELD;
- } else if ( fieldWidth == 0 ) {
- fieldDifference = -1;
- distance += DIFFERENT_FIELD;
- } else if (stringNumeric(inputFieldWidth, fieldWidth,
- (char)(i+BASE) ) ) {
- distance += STRING_NUMERIC_DIFFERENCE;
- } else {
- distance += (inputFieldWidth > fieldWidth) ?
- (inputFieldWidth - fieldWidth) :
- (fieldWidth - inputFieldWidth);
- }
- }
- if ( distance < bestDistance ) {
- bestSkeleton = skeleton;
- bestDistance = distance;
- bestMatchDistanceInfo = fieldDifference;
- }
- if ( distance == 0 ) {
- bestMatchDistanceInfo = 0;
- break;
- }
- }
- if ( replaceZWithV && bestMatchDistanceInfo != -1 ) {
- bestMatchDistanceInfo = 2;
- }
- return bestSkeleton;
-}
-
-
-
-DateIntervalInfo::IntervalPatternIndex
-DateIntervalInfo::calendarFieldToIntervalIndex(UCalendarDateFields field,
- UErrorCode& status) {
- if ( U_FAILURE(status) ) {
- return kIPI_MAX_INDEX;
- }
- IntervalPatternIndex index = kIPI_MAX_INDEX;
- switch ( field ) {
- case UCAL_ERA:
- index = kIPI_ERA;
- break;
- case UCAL_YEAR:
- index = kIPI_YEAR;
- break;
- case UCAL_MONTH:
- index = kIPI_MONTH;
- break;
- case UCAL_DATE:
- case UCAL_DAY_OF_WEEK:
- //case UCAL_DAY_OF_MONTH:
- index = kIPI_DATE;
- break;
- case UCAL_AM_PM:
- index = kIPI_AM_PM;
- break;
- case UCAL_HOUR:
- case UCAL_HOUR_OF_DAY:
- index = kIPI_HOUR;
- break;
- case UCAL_MINUTE:
- index = kIPI_MINUTE;
- break;
- default:
- status = U_ILLEGAL_ARGUMENT_ERROR;
- }
- return index;
-}
-
-
-
-void
-DateIntervalInfo::deleteHash(Hashtable* hTable)
-{
- if ( hTable == NULL ) {
- return;
- }
- int32_t pos = -1;
- const UHashElement* element = NULL;
- while ( (element = hTable->nextElement(pos)) != NULL ) {
- const UHashTok keyTok = element->key;
- const UHashTok valueTok = element->value;
- const UnicodeString* value = (UnicodeString*)valueTok.pointer;
- delete[] value;
- }
- delete fIntervalPatterns;
-}
-
-
-U_CDECL_BEGIN
-
-/**
- * set hash table value comparator
- *
- * @param val1 one value in comparison
- * @param val2 the other value in comparison
- * @return TRUE if 2 values are the same, FALSE otherwise
- */
-UBool U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2);
-
-U_CDECL_END
-
-UBool
-U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2) {
- const UnicodeString* pattern1 = (UnicodeString*)val1.pointer;
- const UnicodeString* pattern2 = (UnicodeString*)val2.pointer;
- UBool ret = TRUE;
- int8_t i;
- for ( i = 0; i < DateIntervalInfo::kIPI_MAX_INDEX && ret == TRUE; ++i ) {
- ret = (pattern1[i] == pattern2[i]);
- }
- return ret;
-}
-
-
-
-Hashtable*
-DateIntervalInfo::initHash(UErrorCode& status) {
- if ( U_FAILURE(status) ) {
- return NULL;
- }
- Hashtable* hTable;
- if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
- hTable->setValueCompartor(dtitvinfHashTableValueComparator);
- return hTable;
-}
-
-
-void
-DateIntervalInfo::copyHash(const Hashtable* source,
- Hashtable* target,
- UErrorCode& status) {
- if ( U_FAILURE(status) ) {
- return;
- }
- int32_t pos = -1;
- const UHashElement* element = NULL;
- if ( source ) {
- while ( (element = source->nextElement(pos)) != NULL ) {
- const UHashTok keyTok = element->key;
- const UnicodeString* key = (UnicodeString*)keyTok.pointer;
- const UHashTok valueTok = element->value;
- const UnicodeString* value = (UnicodeString*)valueTok.pointer;
- UnicodeString* copy = new UnicodeString[kIPI_MAX_INDEX];
- int8_t i;
- for ( i = 0; i < kIPI_MAX_INDEX; ++i ) {
- copy[i] = value[i];
- }
- target->put(UnicodeString(*key), copy, status);
- if ( U_FAILURE(status) ) {
- return;
- }
- }
- }
-}
-
-
-U_NAMESPACE_END
-
-#endif
+/*******************************************************************************
+* Copyright (C) 2008-2009, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File DTITVINF.CPP
+*
+*******************************************************************************
+*/
+
+#include "unicode/dtitvinf.h"
+
+
+#if !UCONFIG_NO_FORMATTING
+
+//TODO: define it in compiler time
+//#define DTITVINF_DEBUG 1
+
+
+#ifdef DTITVINF_DEBUG
+#include <iostream>
+#endif
+
+#include "cstring.h"
+#include "unicode/msgfmt.h"
+#include "dtitv_impl.h"
+#include "hash.h"
+#include "gregoimp.h"
+#include "uresimp.h"
+#include "hash.h"
+#include "gregoimp.h"
+#include "uresimp.h"
+
+
+U_NAMESPACE_BEGIN
+
+
+#ifdef DTITVINF_DEBUG
+#define PRINTMESG(msg) { std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; }
+#endif
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalInfo)
+
+static const char gCalendarTag[]="calendar";
+static const char gGregorianTag[]="gregorian";
+static const char gIntervalDateTimePatternTag[]="intervalFormats";
+static const char gFallbackPatternTag[]="fallback";
+
+// {0}
+static const UChar gFirstPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET};
+// {1}
+static const UChar gSecondPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ONE, RIGHT_CURLY_BRACKET};
+
+// default fall-back
+static const UChar gDefaultFallbackPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, EN_DASH, SPACE, LEFT_CURLY_BRACKET, DIGIT_ONE, RIGHT_CURLY_BRACKET, 0};
+
+
+
+DateIntervalInfo::DateIntervalInfo(UErrorCode& status)
+: fFallbackIntervalPattern(gDefaultFallbackPattern),
+ fFirstDateInPtnIsLaterDate(false),
+ fIntervalPatterns(NULL)
+{
+ fIntervalPatterns = initHash(status);
+}
+
+
+
+DateIntervalInfo::DateIntervalInfo(const Locale& locale, UErrorCode& status)
+: fFallbackIntervalPattern(gDefaultFallbackPattern),
+ fFirstDateInPtnIsLaterDate(false),
+ fIntervalPatterns(NULL)
+{
+ initializeData(locale, status);
+}
+
+
+
+void
+DateIntervalInfo::setIntervalPattern(const UnicodeString& skeleton,
+ UCalendarDateFields lrgDiffCalUnit,
+ const UnicodeString& intervalPattern,
+ UErrorCode& status) {
+
+ if ( lrgDiffCalUnit == UCAL_HOUR_OF_DAY ) {
+ setIntervalPatternInternally(skeleton, UCAL_AM_PM, intervalPattern, status);
+ setIntervalPatternInternally(skeleton, UCAL_HOUR, intervalPattern, status);
+ } else if ( lrgDiffCalUnit == UCAL_DAY_OF_MONTH ||
+ lrgDiffCalUnit == UCAL_DAY_OF_WEEK ) {
+ setIntervalPatternInternally(skeleton, UCAL_DATE, intervalPattern, status);
+ } else {
+ setIntervalPatternInternally(skeleton, lrgDiffCalUnit, intervalPattern, status);
+ }
+}
+
+
+void
+DateIntervalInfo::setFallbackIntervalPattern(
+ const UnicodeString& fallbackPattern,
+ UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ int32_t firstPatternIndex = fallbackPattern.indexOf(gFirstPattern,
+ sizeof(gFirstPattern)/sizeof(gFirstPattern[0]), 0);
+ int32_t secondPatternIndex = fallbackPattern.indexOf(gSecondPattern,
+ sizeof(gSecondPattern)/sizeof(gSecondPattern[0]), 0);
+ if ( firstPatternIndex == -1 || secondPatternIndex == -1 ) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ if ( firstPatternIndex > secondPatternIndex ) {
+ fFirstDateInPtnIsLaterDate = true;
+ }
+ fFallbackIntervalPattern = fallbackPattern;
+}
+
+
+
+DateIntervalInfo::DateIntervalInfo(const DateIntervalInfo& dtitvinf)
+: UObject(dtitvinf),
+ fIntervalPatterns(NULL)
+{
+ *this = dtitvinf;
+}
+
+
+
+DateIntervalInfo&
+DateIntervalInfo::operator=(const DateIntervalInfo& dtitvinf) {
+ if ( this == &dtitvinf ) {
+ return *this;
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ deleteHash(fIntervalPatterns);
+ fIntervalPatterns = initHash(status);
+ copyHash(dtitvinf.fIntervalPatterns, fIntervalPatterns, status);
+ if ( U_FAILURE(status) ) {
+ return *this;
+ }
+
+ fFallbackIntervalPattern = dtitvinf.fFallbackIntervalPattern;
+ fFirstDateInPtnIsLaterDate = dtitvinf.fFirstDateInPtnIsLaterDate;
+ return *this;
+}
+
+
+DateIntervalInfo*
+DateIntervalInfo::clone() const {
+ return new DateIntervalInfo(*this);
+}
+
+
+DateIntervalInfo::~DateIntervalInfo() {
+ deleteHash(fIntervalPatterns);
+ fIntervalPatterns = NULL;
+}
+
+
+UBool
+DateIntervalInfo::operator==(const DateIntervalInfo& other) const {
+ UBool equal = (
+ fFallbackIntervalPattern == other.fFallbackIntervalPattern &&
+ fFirstDateInPtnIsLaterDate == other.fFirstDateInPtnIsLaterDate );
+
+ if ( equal == TRUE ) {
+ equal = fIntervalPatterns->equals(*(other.fIntervalPatterns));
+ }
+
+ return equal;
+}
+
+
+UnicodeString&
+DateIntervalInfo::getIntervalPattern(const UnicodeString& skeleton,
+ UCalendarDateFields field,
+ UnicodeString& result,
+ UErrorCode& status) const {
+ if ( U_FAILURE(status) ) {
+ return result;
+ }
+
+ const UnicodeString* patternsOfOneSkeleton = (UnicodeString*) fIntervalPatterns->get(skeleton);
+ if ( patternsOfOneSkeleton != NULL ) {
+ IntervalPatternIndex index = calendarFieldToIntervalIndex(field, status);
+ if ( U_FAILURE(status) ) {
+ return result;
+ }
+ const UnicodeString& intervalPattern = patternsOfOneSkeleton[index];
+ if ( !intervalPattern.isEmpty() ) {
+ result = intervalPattern;
+ }
+ }
+ return result;
+}
+
+
+UBool
+DateIntervalInfo::getDefaultOrder() const {
+ return fFirstDateInPtnIsLaterDate;
+}
+
+
+UnicodeString&
+DateIntervalInfo::getFallbackIntervalPattern(UnicodeString& result) const {
+ result = fFallbackIntervalPattern;
+ return result;
+}
+
+
+void
+DateIntervalInfo::initializeData(const Locale& locale, UErrorCode& err)
+{
+ fIntervalPatterns = initHash(err);
+ if ( U_FAILURE(err) ) {
+ return;
+ }
+ const char *locName = locale.getName();
+ char parentLocale[ULOC_FULLNAME_CAPACITY];
+ int32_t locNameLen;
+ uprv_strcpy(parentLocale, locName);
+ UErrorCode status = U_ZERO_ERROR;
+ Hashtable skeletonSet(TRUE, status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ do {
+ UResourceBundle *rb, *calBundle, *gregorianBundle, *itvDtPtnResource;
+ rb = ures_open(NULL, parentLocale, &status);
+ calBundle = ures_getByKey(rb, gCalendarTag, NULL, &status);
+ gregorianBundle = ures_getByKey(calBundle, gGregorianTag, NULL, &status);
+ itvDtPtnResource = ures_getByKeyWithFallback(gregorianBundle,
+ gIntervalDateTimePatternTag, NULL, &status);
+
+ if ( U_SUCCESS(status) ) {
+ // look for fallback first, since it establishes the default order
+ const UChar* resStr;
+ int32_t resStrLen = 0;
+ resStr = ures_getStringByKeyWithFallback(itvDtPtnResource,
+ gFallbackPatternTag,
+ &resStrLen, &status);
+ if ( U_SUCCESS(status) ) {
+ UnicodeString pattern = UnicodeString(TRUE, resStr, resStrLen);
+ setFallbackIntervalPattern(pattern, status);
+ }
+
+ int32_t size = ures_getSize(itvDtPtnResource);
+ int32_t index;
+ for ( index = 0; index < size; ++index ) {
+ UResourceBundle* oneRes = ures_getByIndex(itvDtPtnResource, index,
+ NULL, &status);
+ if ( U_SUCCESS(status) ) {
+ const char* skeleton = ures_getKey(oneRes);
+ if ( skeleton == NULL ||
+ skeletonSet.geti(UnicodeString(skeleton)) == 1 ) {
+ ures_close(oneRes);
+ continue;
+ }
+ skeletonSet.puti(UnicodeString(skeleton), 1, status);
+ if ( uprv_strcmp(skeleton, gFallbackPatternTag) == 0 ) {
+ ures_close(oneRes);
+ continue; // fallback
+ }
+
+ UResourceBundle* intervalPatterns = ures_getByKey(
+ itvDtPtnResource, skeleton, NULL, &status);
+
+ if ( U_FAILURE(status) ) {
+ ures_close(intervalPatterns);
+ ures_close(oneRes);
+ break;
+ }
+ if ( intervalPatterns == NULL ) {
+ ures_close(intervalPatterns);
+ ures_close(oneRes);
+ continue;
+ }
+
+ const UChar* pattern;
+ const char* key;
+ int32_t ptLength;
+ int32_t ptnNum = ures_getSize(intervalPatterns);
+ int32_t ptnIndex;
+ for ( ptnIndex = 0; ptnIndex < ptnNum; ++ptnIndex ) {
+ pattern = ures_getNextString(intervalPatterns, &ptLength, &key,
+ &status);
+ if ( U_FAILURE(status) ) {
+ break;
+ }
+
+ UCalendarDateFields calendarField = UCAL_FIELD_COUNT;
+ if ( !uprv_strcmp(key, "y") ) {
+ calendarField = UCAL_YEAR;
+ } else if ( !uprv_strcmp(key, "M") ) {
+ calendarField = UCAL_MONTH;
+ } else if ( !uprv_strcmp(key, "d") ) {
+ calendarField = UCAL_DATE;
+ } else if ( !uprv_strcmp(key, "a") ) {
+ calendarField = UCAL_AM_PM;
+ } else if ( !uprv_strcmp(key, "h") ) {
+ calendarField = UCAL_HOUR;
+ } else if ( !uprv_strcmp(key, "m") ) {
+ calendarField = UCAL_MINUTE;
+ }
+ if ( calendarField != UCAL_FIELD_COUNT ) {
+ setIntervalPatternInternally(skeleton, calendarField, pattern,status);
+ }
+ }
+ ures_close(intervalPatterns);
+ }
+ ures_close(oneRes);
+ }
+ }
+ ures_close(itvDtPtnResource);
+ ures_close(gregorianBundle);
+ ures_close(calBundle);
+ ures_close(rb);
+ status = U_ZERO_ERROR;
+ locNameLen = uloc_getParent(parentLocale, parentLocale,
+ ULOC_FULLNAME_CAPACITY,&status);
+ } while ( locNameLen > 0 );
+}
+
+
+
+void
+DateIntervalInfo::setIntervalPatternInternally(const UnicodeString& skeleton,
+ UCalendarDateFields lrgDiffCalUnit,
+ const UnicodeString& intervalPattern,
+ UErrorCode& status) {
+ IntervalPatternIndex index = calendarFieldToIntervalIndex(lrgDiffCalUnit,status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ UnicodeString* patternsOfOneSkeleton = (UnicodeString*)(fIntervalPatterns->get(skeleton));
+ UBool emptyHash = false;
+ if ( patternsOfOneSkeleton == NULL ) {
+ patternsOfOneSkeleton = new UnicodeString[kIPI_MAX_INDEX];
+ emptyHash = true;
+ }
+
+ patternsOfOneSkeleton[index] = intervalPattern;
+ if ( emptyHash == TRUE ) {
+ fIntervalPatterns->put(skeleton, patternsOfOneSkeleton, status);
+ }
+}
+
+
+
+void
+DateIntervalInfo::parseSkeleton(const UnicodeString& skeleton,
+ int32_t* skeletonFieldWidth) {
+ const int8_t PATTERN_CHAR_BASE = 0x41;
+ int32_t i;
+ for ( i = 0; i < skeleton.length(); ++i ) {
+ // it is an ASCII char in skeleton
+ int8_t ch = (int8_t)skeleton.charAt(i);
+ ++skeletonFieldWidth[ch - PATTERN_CHAR_BASE];
+ }
+}
+
+
+
+UBool
+DateIntervalInfo::stringNumeric(int32_t fieldWidth, int32_t anotherFieldWidth,
+ char patternLetter) {
+ if ( patternLetter == 'M' ) {
+ if ( fieldWidth <= 2 && anotherFieldWidth > 2 ||
+ fieldWidth > 2 && anotherFieldWidth <= 2 ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+const UnicodeString*
+DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton,
+ int8_t& bestMatchDistanceInfo) const {
+#ifdef DTITVINF_DEBUG
+ char result[1000];
+ char result_1[1000];
+ char mesg[2000];
+ skeleton.extract(0, skeleton.length(), result, "UTF-8");
+ sprintf(mesg, "in getBestSkeleton: skeleton: %s; \n", result);
+ PRINTMESG(mesg)
+#endif
+
+
+ int32_t inputSkeletonFieldWidth[] =
+ {
+ // A B C D E F G H I J K L M N O
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // P Q R S T U V W X Y Z
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // a b c d e f g h i j k l m n o
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // p q r s t u v w x y z
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ int32_t skeletonFieldWidth[] =
+ {
+ // A B C D E F G H I J K L M N O
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // P Q R S T U V W X Y Z
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // a b c d e f g h i j k l m n o
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ // p q r s t u v w x y z
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ const int32_t DIFFERENT_FIELD = 0x1000;
+ const int32_t STRING_NUMERIC_DIFFERENCE = 0x100;
+ const int32_t BASE = 0x41;
+ const UChar CHAR_V = 0x0076;
+ const UChar CHAR_Z = 0x007A;
+
+ // hack for 'v' and 'z'.
+ // resource bundle only have time skeletons ending with 'v',
+ // but not for time skeletons ending with 'z'.
+ UBool replaceZWithV = false;
+ const UnicodeString* inputSkeleton = &skeleton;
+ UnicodeString copySkeleton;
+ if ( skeleton.indexOf(CHAR_Z) != -1 ) {
+ UChar zstr[2];
+ UChar vstr[2];
+ zstr[0]=CHAR_Z;
+ vstr[0]=CHAR_V;
+ zstr[1]=0;
+ vstr[1]=0;
+ copySkeleton = skeleton;
+ copySkeleton.findAndReplace(zstr, vstr);
+ inputSkeleton = ©Skeleton;
+ replaceZWithV = true;
+ }
+
+ parseSkeleton(*inputSkeleton, inputSkeletonFieldWidth);
+ int32_t bestDistance = MAX_POSITIVE_INT;
+ const UnicodeString* bestSkeleton = NULL;
+
+ // 0 means exact the same skeletons;
+ // 1 means having the same field, but with different length,
+ // 2 means only z/v differs
+ // -1 means having different field.
+ bestMatchDistanceInfo = 0;
+ int8_t fieldLength = sizeof(skeletonFieldWidth)/sizeof(skeletonFieldWidth[0]);
+
+ int32_t pos = -1;
+ const UHashElement* elem = NULL;
+ while ( (elem = fIntervalPatterns->nextElement(pos)) != NULL ) {
+ const UHashTok keyTok = elem->key;
+ UnicodeString* skeleton = (UnicodeString*)keyTok.pointer;
+#ifdef DTITVINF_DEBUG
+ skeleton->extract(0, skeleton->length(), result, "UTF-8");
+ sprintf(mesg, "available skeletons: skeleton: %s; \n", result);
+ PRINTMESG(mesg)
+#endif
+
+ // clear skeleton field width
+ int8_t i;
+ for ( i = 0; i < fieldLength; ++i ) {
+ skeletonFieldWidth[i] = 0;
+ }
+ parseSkeleton(*skeleton, skeletonFieldWidth);
+ // calculate distance
+ int32_t distance = 0;
+ int8_t fieldDifference = 1;
+ for ( i = 0; i < fieldLength; ++i ) {
+ int32_t inputFieldWidth = inputSkeletonFieldWidth[i];
+ int32_t fieldWidth = skeletonFieldWidth[i];
+ if ( inputFieldWidth == fieldWidth ) {
+ continue;
+ }
+ if ( inputFieldWidth == 0 ) {
+ fieldDifference = -1;
+ distance += DIFFERENT_FIELD;
+ } else if ( fieldWidth == 0 ) {
+ fieldDifference = -1;
+ distance += DIFFERENT_FIELD;
+ } else if (stringNumeric(inputFieldWidth, fieldWidth,
+ (char)(i+BASE) ) ) {
+ distance += STRING_NUMERIC_DIFFERENCE;
+ } else {
+ distance += (inputFieldWidth > fieldWidth) ?
+ (inputFieldWidth - fieldWidth) :
+ (fieldWidth - inputFieldWidth);
+ }
+ }
+ if ( distance < bestDistance ) {
+ bestSkeleton = skeleton;
+ bestDistance = distance;
+ bestMatchDistanceInfo = fieldDifference;
+ }
+ if ( distance == 0 ) {
+ bestMatchDistanceInfo = 0;
+ break;
+ }
+ }
+ if ( replaceZWithV && bestMatchDistanceInfo != -1 ) {
+ bestMatchDistanceInfo = 2;
+ }
+ return bestSkeleton;
+}
+
+
+
+DateIntervalInfo::IntervalPatternIndex
+DateIntervalInfo::calendarFieldToIntervalIndex(UCalendarDateFields field,
+ UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return kIPI_MAX_INDEX;
+ }
+ IntervalPatternIndex index = kIPI_MAX_INDEX;
+ switch ( field ) {
+ case UCAL_ERA:
+ index = kIPI_ERA;
+ break;
+ case UCAL_YEAR:
+ index = kIPI_YEAR;
+ break;
+ case UCAL_MONTH:
+ index = kIPI_MONTH;
+ break;
+ case UCAL_DATE:
+ case UCAL_DAY_OF_WEEK:
+ //case UCAL_DAY_OF_MONTH:
+ index = kIPI_DATE;
+ break;
+ case UCAL_AM_PM:
+ index = kIPI_AM_PM;
+ break;
+ case UCAL_HOUR:
+ case UCAL_HOUR_OF_DAY:
+ index = kIPI_HOUR;
+ break;
+ case UCAL_MINUTE:
+ index = kIPI_MINUTE;
+ break;
+ default:
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ return index;
+}
+
+
+
+void
+DateIntervalInfo::deleteHash(Hashtable* hTable)
+{
+ if ( hTable == NULL ) {
+ return;
+ }
+ int32_t pos = -1;
+ const UHashElement* element = NULL;
+ while ( (element = hTable->nextElement(pos)) != NULL ) {
+ const UHashTok keyTok = element->key;
+ const UHashTok valueTok = element->value;
+ const UnicodeString* value = (UnicodeString*)valueTok.pointer;
+ delete[] value;
+ }
+ delete fIntervalPatterns;
+}
+
+
+U_CDECL_BEGIN
+
+/**
+ * set hash table value comparator
+ *
+ * @param val1 one value in comparison
+ * @param val2 the other value in comparison
+ * @return TRUE if 2 values are the same, FALSE otherwise
+ */
+UBool U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2);
+
+U_CDECL_END
+
+UBool
+U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2) {
+ const UnicodeString* pattern1 = (UnicodeString*)val1.pointer;
+ const UnicodeString* pattern2 = (UnicodeString*)val2.pointer;
+ UBool ret = TRUE;
+ int8_t i;
+ for ( i = 0; i < DateIntervalInfo::kIPI_MAX_INDEX && ret == TRUE; ++i ) {
+ ret = (pattern1[i] == pattern2[i]);
+ }
+ return ret;
+}
+
+
+
+Hashtable*
+DateIntervalInfo::initHash(UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return NULL;
+ }
+ Hashtable* hTable;
+ if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ hTable->setValueCompartor(dtitvinfHashTableValueComparator);
+ return hTable;
+}
+
+
+void
+DateIntervalInfo::copyHash(const Hashtable* source,
+ Hashtable* target,
+ UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ int32_t pos = -1;
+ const UHashElement* element = NULL;
+ if ( source ) {
+ while ( (element = source->nextElement(pos)) != NULL ) {
+ const UHashTok keyTok = element->key;
+ const UnicodeString* key = (UnicodeString*)keyTok.pointer;
+ const UHashTok valueTok = element->value;
+ const UnicodeString* value = (UnicodeString*)valueTok.pointer;
+ UnicodeString* copy = new UnicodeString[kIPI_MAX_INDEX];
+ int8_t i;
+ for ( i = 0; i < kIPI_MAX_INDEX; ++i ) {
+ copy[i] = value[i];
+ }
+ target->put(UnicodeString(*key), copy, status);
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ }
+ }
+}
+
+
+U_NAMESPACE_END
+
+#endif
Modified: trunk/source/i18n/dtptngen.cpp
===================================================================
--- trunk/source/i18n/dtptngen.cpp 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/i18n/dtptngen.cpp 2009-07-02 19:32:00 UTC (rev 214)
@@ -385,7 +385,7 @@
if (U_FAILURE(status)) {
return;
}
- addCLDRData(locale);
+ addCLDRData(locale, status);
setDateTimeFromCalendar(locale, status);
setDecimalSymbols(locale, status);
} // DateTimePatternGenerator::initData
@@ -497,8 +497,7 @@
static const UChar hourFormatChars[] = { CAP_H, LOW_H, CAP_K, LOW_K, 0 }; // HhKk, the hour format characters
void
-DateTimePatternGenerator::addCLDRData(const Locale& locale) {
- UErrorCode err = U_ZERO_ERROR;
+DateTimePatternGenerator::addCLDRData(const Locale& locale, UErrorCode& err) {
UResourceBundle *rb, *calTypeBundle, *calBundle;
UResourceBundle *patBundle, *fieldBundle, *fBundle;
UnicodeString rbPattern, value, field;
@@ -509,6 +508,8 @@
UnicodeString defaultItemFormat(TRUE, UDATPG_ItemFormat, LENGTHOF(UDATPG_ItemFormat)-1); // Read-only alias.
+ err = U_ZERO_ERROR;
+
fDefaultHourFormatChar = 0;
for (i=0; i<UDATPG_FIELD_COUNT; ++i ) {
appendItemNames[i]=CAP_F;
@@ -524,6 +525,9 @@
}
rb = ures_open(NULL, locale.getName(), &err);
+ if (rb == NULL || U_FAILURE(err)) {
+ return;
+ }
const char *curLocaleName=ures_getLocaleByType(rb, ULOC_ACTUAL_LOCALE, &err);
const char * calendarTypeToUse = DT_DateTimeGregorianTag; // initial default
char calendarType[ULOC_KEYWORDS_CAPACITY]; // to be filled in with the type to use, if all goes well
@@ -570,7 +574,7 @@
}
}
}
- };
+ }
ures_close(patBundle);
err = U_ZERO_ERROR;
@@ -596,7 +600,7 @@
patBundle = ures_getByKeyWithFallback(fBundle, Resource_Fields[i], NULL, &err);
fieldBundle = ures_getByKeyWithFallback(patBundle, "dn", NULL, &err);
rbPattern = ures_getNextUnicodeString(fieldBundle, &key, &err);
- ures_close(fieldBundle);
+ ures_close(fieldBundle);
ures_close(patBundle);
if (rbPattern.length()==0 ) {
continue;
Modified: trunk/source/i18n/tmunit.cpp
===================================================================
--- trunk/source/i18n/tmunit.cpp 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/i18n/tmunit.cpp 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,115 +1,115 @@
-/*
- *******************************************************************************
- * Copyright (C) 2008, Google, International Business Machines Corporation and *
- * others. All Rights Reserved. *
- *******************************************************************************
- */
-
-#include "unicode/tmunit.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-U_NAMESPACE_BEGIN
-
-UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeUnit)
-
-
-/*
- * There are only 7 time units.
- * So, TimeUnit could be made as singleton
- * (similar to uniset_props.cpp, or unorm.cpp,
- * in which a static TimeUnit* array is created, and
- * the creatInstance() returns a const TimeUnit*).
- * But the constraint is TimeUnit is a data member of Measure.
- * But Measure (which is an existing API) does not expect it's "unit" member
- * as singleton. Meaure takes ownership of the "unit" member.
- * In its constructor, it does not take a const "unit" pointer.
- * Also, Measure can clone and destruct the "unit" pointer.
- * In order to preserve the old behavior and let Measure handle singleton "unit",
- * 1. a flag need to be added in Measure;
- * 2. a new constructor which takes const "unit" as parameter need to be added,
- * and this new constructor will set the flag on.
- * 3. clone and destructor need to check upon this flag to distinguish on how
- * to handle the "unit".
- *
- * Since TimeUnit is such a light weight object, comparing with the heavy weight
- * format operation, we decided to avoid the above complication.
- *
- * So, both TimeUnit and CurrencyUnit (the 2 subclasses of MeasureUnit) are
- * immutable and non-singleton.
- *
- * Currently, TimeUnitAmount and CurrencyAmount are immutable.
- * If an application needs to create a long list of TimeUnitAmount on the same
- * time unit but different number, for example,
- * 1 hour, 2 hour, 3 hour, ................. 10,000 hour,
- * there might be performance hit because 10,000 TimeUnit object,
- * although all are the same time unit, will be created in heap and deleted.
- *
- * To address this performance issue, if there is any in the future,
- * we should and need to change TimeUnitAmount and CurrencyAmount to be
- * immutable by allowing a setter on the number.
- * Or we need to add 2 parallel mutable classes in order to
- * preserve the existing API.
- * Or we can use freezable.
- */
-TimeUnit* U_EXPORT2
-TimeUnit::createInstance(TimeUnit::UTimeUnitFields timeUnitField,
- UErrorCode& status) {
- if (U_FAILURE(status)) {
- return NULL;
- }
- if (timeUnitField < 0 || timeUnitField >= UTIMEUNIT_FIELD_COUNT) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return NULL;
- }
- return new TimeUnit(timeUnitField);
-}
-
-
-TimeUnit::TimeUnit(TimeUnit::UTimeUnitFields timeUnitField) {
- fTimeUnitField = timeUnitField;
-}
-
-
-TimeUnit::TimeUnit(const TimeUnit& other)
-: MeasureUnit(other) {
- *this = other;
-}
-
-
-UObject*
-TimeUnit::clone() const {
- return new TimeUnit(*this);
-}
-
-
-TimeUnit&
-TimeUnit::operator=(const TimeUnit& other) {
- if (this == &other) {
- return *this;
- }
- fTimeUnitField = other.fTimeUnitField;
- return *this;
-}
-
-
-UBool
-TimeUnit::operator==(const UObject& other) const {
- return (other.getDynamicClassID() == TimeUnit::getStaticClassID()
- && fTimeUnitField == ((TimeUnit*)&other)->fTimeUnitField);
-}
-
-
-TimeUnit::UTimeUnitFields
-TimeUnit::getTimeUnitField() const {
- return fTimeUnitField;
-}
-
-
-TimeUnit::~TimeUnit() {
-}
-
-
-U_NAMESPACE_END
-
-#endif
+/*
+ *******************************************************************************
+ * Copyright (C) 2008, Google, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+
+#include "unicode/tmunit.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeUnit)
+
+
+/*
+ * There are only 7 time units.
+ * So, TimeUnit could be made as singleton
+ * (similar to uniset_props.cpp, or unorm.cpp,
+ * in which a static TimeUnit* array is created, and
+ * the creatInstance() returns a const TimeUnit*).
+ * But the constraint is TimeUnit is a data member of Measure.
+ * But Measure (which is an existing API) does not expect it's "unit" member
+ * as singleton. Meaure takes ownership of the "unit" member.
+ * In its constructor, it does not take a const "unit" pointer.
+ * Also, Measure can clone and destruct the "unit" pointer.
+ * In order to preserve the old behavior and let Measure handle singleton "unit",
+ * 1. a flag need to be added in Measure;
+ * 2. a new constructor which takes const "unit" as parameter need to be added,
+ * and this new constructor will set the flag on.
+ * 3. clone and destructor need to check upon this flag to distinguish on how
+ * to handle the "unit".
+ *
+ * Since TimeUnit is such a light weight object, comparing with the heavy weight
+ * format operation, we decided to avoid the above complication.
+ *
+ * So, both TimeUnit and CurrencyUnit (the 2 subclasses of MeasureUnit) are
+ * immutable and non-singleton.
+ *
+ * Currently, TimeUnitAmount and CurrencyAmount are immutable.
+ * If an application needs to create a long list of TimeUnitAmount on the same
+ * time unit but different number, for example,
+ * 1 hour, 2 hour, 3 hour, ................. 10,000 hour,
+ * there might be performance hit because 10,000 TimeUnit object,
+ * although all are the same time unit, will be created in heap and deleted.
+ *
+ * To address this performance issue, if there is any in the future,
+ * we should and need to change TimeUnitAmount and CurrencyAmount to be
+ * immutable by allowing a setter on the number.
+ * Or we need to add 2 parallel mutable classes in order to
+ * preserve the existing API.
+ * Or we can use freezable.
+ */
+TimeUnit* U_EXPORT2
+TimeUnit::createInstance(TimeUnit::UTimeUnitFields timeUnitField,
+ UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ if (timeUnitField < 0 || timeUnitField >= UTIMEUNIT_FIELD_COUNT) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+ return new TimeUnit(timeUnitField);
+}
+
+
+TimeUnit::TimeUnit(TimeUnit::UTimeUnitFields timeUnitField) {
+ fTimeUnitField = timeUnitField;
+}
+
+
+TimeUnit::TimeUnit(const TimeUnit& other)
+: MeasureUnit(other) {
+ *this = other;
+}
+
+
+UObject*
+TimeUnit::clone() const {
+ return new TimeUnit(*this);
+}
+
+
+TimeUnit&
+TimeUnit::operator=(const TimeUnit& other) {
+ if (this == &other) {
+ return *this;
+ }
+ fTimeUnitField = other.fTimeUnitField;
+ return *this;
+}
+
+
+UBool
+TimeUnit::operator==(const UObject& other) const {
+ return (other.getDynamicClassID() == TimeUnit::getStaticClassID()
+ && fTimeUnitField == ((TimeUnit*)&other)->fTimeUnitField);
+}
+
+
+TimeUnit::UTimeUnitFields
+TimeUnit::getTimeUnitField() const {
+ return fTimeUnitField;
+}
+
+
+TimeUnit::~TimeUnit() {
+}
+
+
+U_NAMESPACE_END
+
+#endif
Modified: trunk/source/i18n/tmutamt.cpp
===================================================================
--- trunk/source/i18n/tmutamt.cpp 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/i18n/tmutamt.cpp 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,76 +1,76 @@
-/*
- *******************************************************************************
- * Copyright (C) 2008, Google, International Business Machines Corporation and *
- * others. All Rights Reserved. *
- *******************************************************************************
- */
-
-#include "unicode/tmutamt.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-U_NAMESPACE_BEGIN
-
-UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeUnitAmount)
-
-
-TimeUnitAmount::TimeUnitAmount(const Formattable& number,
- TimeUnit::UTimeUnitFields timeUnitField,
- UErrorCode& status)
-: Measure(number, TimeUnit::createInstance(timeUnitField, status), status) {
-}
-
-
-TimeUnitAmount::TimeUnitAmount(double amount,
- TimeUnit::UTimeUnitFields timeUnitField,
- UErrorCode& status)
-: Measure(Formattable(amount),
- TimeUnit::createInstance(timeUnitField, status),
- status) {
-}
-
-
-TimeUnitAmount::TimeUnitAmount(const TimeUnitAmount& other)
-: Measure(other)
-{
-}
-
-
-TimeUnitAmount&
-TimeUnitAmount::operator=(const TimeUnitAmount& other) {
- Measure::operator=(other);
- return *this;
-}
-
-
-UBool
-TimeUnitAmount::operator==(const UObject& other) const {
- return Measure::operator==(other);
-}
-
-UObject*
-TimeUnitAmount::clone() const {
- return new TimeUnitAmount(*this);
-}
-
-
-TimeUnitAmount::~TimeUnitAmount() {
-}
-
-
-
-const TimeUnit&
-TimeUnitAmount::getTimeUnit() const {
- return (const TimeUnit&) getUnit();
-}
-
-
-TimeUnit::UTimeUnitFields
-TimeUnitAmount::getTimeUnitField() const {
- return getTimeUnit().getTimeUnitField();
-}
-
-
-U_NAMESPACE_END
-
-#endif
+/*
+ *******************************************************************************
+ * Copyright (C) 2008, Google, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+
+#include "unicode/tmutamt.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeUnitAmount)
+
+
+TimeUnitAmount::TimeUnitAmount(const Formattable& number,
+ TimeUnit::UTimeUnitFields timeUnitField,
+ UErrorCode& status)
+: Measure(number, TimeUnit::createInstance(timeUnitField, status), status) {
+}
+
+
+TimeUnitAmount::TimeUnitAmount(double amount,
+ TimeUnit::UTimeUnitFields timeUnitField,
+ UErrorCode& status)
+: Measure(Formattable(amount),
+ TimeUnit::createInstance(timeUnitField, status),
+ status) {
+}
+
+
+TimeUnitAmount::TimeUnitAmount(const TimeUnitAmount& other)
+: Measure(other)
+{
+}
+
+
+TimeUnitAmount&
+TimeUnitAmount::operator=(const TimeUnitAmount& other) {
+ Measure::operator=(other);
+ return *this;
+}
+
+
+UBool
+TimeUnitAmount::operator==(const UObject& other) const {
+ return Measure::operator==(other);
+}
+
+UObject*
+TimeUnitAmount::clone() const {
+ return new TimeUnitAmount(*this);
+}
+
+
+TimeUnitAmount::~TimeUnitAmount() {
+}
+
+
+
+const TimeUnit&
+TimeUnitAmount::getTimeUnit() const {
+ return (const TimeUnit&) getUnit();
+}
+
+
+TimeUnit::UTimeUnitFields
+TimeUnitAmount::getTimeUnitField() const {
+ return getTimeUnit().getTimeUnitField();
+}
+
+
+U_NAMESPACE_END
+
+#endif
Modified: trunk/source/i18n/tmutfmt.cpp
===================================================================
--- trunk/source/i18n/tmutfmt.cpp 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/i18n/tmutfmt.cpp 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,859 +1,859 @@
-/*
- *******************************************************************************
- * Copyright (C) 2008-2009, Google, International Business Machines Corporation
- * and others. All Rights Reserved.
- *******************************************************************************
- */
-
-
-#include "unicode/tmutfmt.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "cmemory.h"
-#include "cstring.h"
-#include "hash.h"
-#include "uresimp.h"
-#include "unicode/msgfmt.h"
-
-#define LEFT_CURLY_BRACKET ((UChar)0x007B)
-#define RIGHT_CURLY_BRACKET ((UChar)0x007D)
-#define SPACE ((UChar)0x0020)
-#define DIGIT_ZERO ((UChar)0x0030)
-#define LOW_S ((UChar)0x0073)
-#define LOW_M ((UChar)0x006D)
-#define LOW_I ((UChar)0x0069)
-#define LOW_N ((UChar)0x006E)
-#define LOW_H ((UChar)0x0068)
-#define LOW_W ((UChar)0x0077)
-#define LOW_D ((UChar)0x0064)
-#define LOW_Y ((UChar)0x0079)
-#define LOW_Z ((UChar)0x007A)
-#define LOW_E ((UChar)0x0065)
-#define LOW_R ((UChar)0x0072)
-#define LOW_O ((UChar)0x006F)
-#define LOW_N ((UChar)0x006E)
-#define LOW_T ((UChar)0x0074)
-
-
-//TODO: define in compile time
-//#define TMUTFMT_DEBUG 1
-
-#ifdef TMUTFMT_DEBUG
-#include <iostream>
-#endif
-
-U_NAMESPACE_BEGIN
-
-
-
-UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeUnitFormat)
-
-static const char gUnitsTag[] = "units";
-static const char gShortUnitsTag[] = "unitsShort";
-static const char gTimeUnitYear[] = "year";
-static const char gTimeUnitMonth[] = "month";
-static const char gTimeUnitDay[] = "day";
-static const char gTimeUnitWeek[] = "week";
-static const char gTimeUnitHour[] = "hour";
-static const char gTimeUnitMinute[] = "minute";
-static const char gTimeUnitSecond[] = "second";
-static const char gPluralCountOther[] = "other";
-
-static const UChar DEFAULT_PATTERN_FOR_SECOND[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_S, 0};
-static const UChar DEFAULT_PATTERN_FOR_MINUTE[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_M, LOW_I, LOW_N, 0};
-static const UChar DEFAULT_PATTERN_FOR_HOUR[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_H, 0};
-static const UChar DEFAULT_PATTERN_FOR_WEEK[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_W, 0};
-static const UChar DEFAULT_PATTERN_FOR_DAY[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_D, 0};
-static const UChar DEFAULT_PATTERN_FOR_MONTH[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_M, 0};
-static const UChar DEFAULT_PATTERN_FOR_YEAR[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_Y, 0};
-
-static const UChar PLURAL_COUNT_ZERO[] = {LOW_Z, LOW_E, LOW_R, LOW_O, 0};
-static const UChar PLURAL_COUNT_ONE[] = {LOW_O, LOW_N, LOW_E, 0};
-static const UChar PLURAL_COUNT_TWO[] = {LOW_T, LOW_W, LOW_O, 0};
-
-
-TimeUnitFormat::TimeUnitFormat(UErrorCode& status)
-: fNumberFormat(NULL),
- fPluralRules(NULL) {
- create(Locale::getDefault(), kFull, status);
-}
-
-
-TimeUnitFormat::TimeUnitFormat(const Locale& locale, UErrorCode& status)
-: fNumberFormat(NULL),
- fPluralRules(NULL) {
- create(locale, kFull, status);
-}
-
-
-TimeUnitFormat::TimeUnitFormat(const Locale& locale, EStyle style, UErrorCode& status)
-: fNumberFormat(NULL),
- fPluralRules(NULL) {
- create(locale, style, status);
-}
-
-
-TimeUnitFormat::TimeUnitFormat(const TimeUnitFormat& other)
-: MeasureFormat(other),
- fNumberFormat(NULL),
- fPluralRules(NULL),
- fStyle(kFull)
-{
- for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
- i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
- i = (TimeUnit::UTimeUnitFields)(i+1)) {
- fTimeUnitToCountToPatterns[i] = NULL;
- }
- *this = other;
-}
-
-
-TimeUnitFormat::~TimeUnitFormat() {
- delete fNumberFormat;
- fNumberFormat = NULL;
- for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
- i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
- i = (TimeUnit::UTimeUnitFields)(i+1)) {
- deleteHash(fTimeUnitToCountToPatterns[i]);
- fTimeUnitToCountToPatterns[i] = NULL;
- }
- delete fPluralRules;
- fPluralRules = NULL;
-}
-
-
-Format*
-TimeUnitFormat::clone(void) const {
- return new TimeUnitFormat(*this);
-}
-
-
-TimeUnitFormat&
-TimeUnitFormat::operator=(const TimeUnitFormat& other) {
- if (this == &other) {
- return *this;
- }
- delete fNumberFormat;
- for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
- i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
- i = (TimeUnit::UTimeUnitFields)(i+1)) {
- deleteHash(fTimeUnitToCountToPatterns[i]);
- fTimeUnitToCountToPatterns[i] = NULL;
- }
- delete fPluralRules;
- if (other.fNumberFormat) {
- fNumberFormat = (NumberFormat*)other.fNumberFormat->clone();
- } else {
- fNumberFormat = NULL;
- }
- fLocale = other.fLocale;
- for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
- i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
- i = (TimeUnit::UTimeUnitFields)(i+1)) {
- UErrorCode status = U_ZERO_ERROR;
- fTimeUnitToCountToPatterns[i] = initHash(status);
- if (U_SUCCESS(status)) {
- copyHash(other.fTimeUnitToCountToPatterns[i], fTimeUnitToCountToPatterns[i], status);
- } else {
- delete fTimeUnitToCountToPatterns[i];
- fTimeUnitToCountToPatterns[i] = NULL;
- }
- }
- if (other.fPluralRules) {
- fPluralRules = (PluralRules*)other.fPluralRules->clone();
- } else {
- fPluralRules = NULL;
- }
- fStyle = other.fStyle;
- return *this;
-}
-
-
-UBool
-TimeUnitFormat::operator==(const Format& other) const {
- if (other.getDynamicClassID() == TimeUnitFormat::getStaticClassID()) {
- TimeUnitFormat* fmt = (TimeUnitFormat*)&other;
- UBool ret = ( (fNumberFormat && fmt->fNumberFormat &&
- *fNumberFormat == *fmt->fNumberFormat ||
- fNumberFormat == fmt->fNumberFormat ) &&
- fLocale == fmt->fLocale &&
- (fPluralRules && fmt->fPluralRules &&
- *fPluralRules == *fmt->fPluralRules ||
- fPluralRules == fmt->fPluralRules) &&
- fStyle == fmt->fStyle);
- if (ret) {
- for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
- i < TimeUnit::UTIMEUNIT_FIELD_COUNT && ret;
- i = (TimeUnit::UTimeUnitFields)(i+1)) {
- ret = fTimeUnitToCountToPatterns[i]->equals(*(fmt->fTimeUnitToCountToPatterns[i]));
- }
- }
- return ret;
- }
- return false;
-}
-
-
-UnicodeString&
-TimeUnitFormat::format(const Formattable& obj, UnicodeString& toAppendTo,
- FieldPosition& pos, UErrorCode& status) const {
- if (U_FAILURE(status)) {
- return toAppendTo;
- }
- if (obj.getType() == Formattable::kObject) {
- const UObject* formatObj = obj.getObject();
- if (formatObj->getDynamicClassID() == TimeUnitAmount::getStaticClassID()){
- TimeUnitAmount* amount = (TimeUnitAmount*)formatObj;
- Hashtable* countToPattern = fTimeUnitToCountToPatterns[amount->getTimeUnitField()];
- double number;
- const Formattable& amtNumber = amount->getNumber();
- if (amtNumber.getType() == Formattable::kDouble) {
- number = amtNumber.getDouble();
- } else if (amtNumber.getType() == Formattable::kLong) {
- number = amtNumber.getLong();
- } else {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return toAppendTo;
- }
- UnicodeString count = fPluralRules->select(number);
-#ifdef TMUTFMT_DEBUG
- char result[1000];
- count.extract(0, count.length(), result, "UTF-8");
- std::cout << "number: " << number << "; format plural count: " << result << "\n";
-#endif
- MessageFormat* pattern = ((MessageFormat**)countToPattern->get(count))[fStyle];
- Formattable formattable[1];
- formattable[0].setDouble(number);
- return pattern->format(formattable, 1, toAppendTo, pos, status);
- }
- }
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return toAppendTo;
-}
-
-
-void
-TimeUnitFormat::parseObject(const UnicodeString& source,
- Formattable& result,
- ParsePosition& pos) const {
- double resultNumber = -1;
- UBool withNumberFormat = false;
- TimeUnit::UTimeUnitFields resultTimeUnit = TimeUnit::UTIMEUNIT_FIELD_COUNT;
- int32_t oldPos = pos.getIndex();
- int32_t newPos = -1;
- int32_t longestParseDistance = 0;
- UnicodeString* countOfLongestMatch = NULL;
-#ifdef TMUTFMT_DEBUG
- char res[1000];
- source.extract(0, source.length(), res, "UTF-8");
- std::cout << "parse source: " << res << "\n";
-#endif
- // parse by iterating through all available patterns
- // and looking for the longest match.
- for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
- i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
- i = (TimeUnit::UTimeUnitFields)(i+1)) {
- Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i];
- int32_t elemPos = -1;
- const UHashElement* elem = NULL;
- while ((elem = countToPatterns->nextElement(elemPos)) != NULL){
- const UHashTok keyTok = elem->key;
- UnicodeString* count = (UnicodeString*)keyTok.pointer;
-#ifdef TMUTFMT_DEBUG
- count->extract(0, count->length(), res, "UTF-8");
- std::cout << "parse plural count: " << res << "\n";
-#endif
- const UHashTok valueTok = elem->value;
- // the value is a pair of MessageFormat*
- MessageFormat** patterns = (MessageFormat**)valueTok.pointer;
- for (EStyle style = kFull; style < kTotal; style = (EStyle)(style + 1)) {
- MessageFormat* pattern = patterns[style];
- pos.setErrorIndex(-1);
- pos.setIndex(oldPos);
- // see if we can parse
- Formattable parsed;
- pattern->parseObject(source, parsed, pos);
- if (pos.getErrorIndex() != -1 || pos.getIndex() == oldPos) {
- continue;
- }
- #ifdef TMUTFMT_DEBUG
- std::cout << "parsed.getType: " << parsed.getType() << "\n";
- #endif
- double tmpNumber = 0;
- if (pattern->getArgTypeCount() != 0) {
- // pattern with Number as beginning, such as "{0} d".
- // check to make sure that the timeUnit is consistent
- Formattable& temp = parsed[0];
- if (temp.getType() == Formattable::kDouble) {
- tmpNumber = temp.getDouble();
- } else if (temp.getType() == Formattable::kLong) {
- tmpNumber = temp.getLong();
- } else {
- continue;
- }
- UnicodeString select = fPluralRules->select(tmpNumber);
- #ifdef TMUTFMT_DEBUG
- select.extract(0, select.length(), res, "UTF-8");
- std::cout << "parse plural select count: " << res << "\n";
- #endif
- if (*count != select) {
- continue;
- }
- }
- int32_t parseDistance = pos.getIndex() - oldPos;
- if (parseDistance > longestParseDistance) {
- if (pattern->getArgTypeCount() != 0) {
- resultNumber = tmpNumber;
- withNumberFormat = true;
- } else {
- withNumberFormat = false;
- }
- resultTimeUnit = i;
- newPos = pos.getIndex();
- longestParseDistance = parseDistance;
- countOfLongestMatch = count;
- }
- }
- }
- }
- /* After find the longest match, parse the number.
- * Result number could be null for the pattern without number pattern.
- * such as unit pattern in Arabic.
- * When result number is null, use plural rule to set the number.
- */
- if (withNumberFormat == false && longestParseDistance != 0) {
- // set the number using plurrual count
- if ( *countOfLongestMatch == PLURAL_COUNT_ZERO ) {
- resultNumber = 0;
- } else if ( *countOfLongestMatch == PLURAL_COUNT_ONE ) {
- resultNumber = 1;
- } else if ( *countOfLongestMatch == PLURAL_COUNT_TWO ) {
- resultNumber = 2;
- } else {
- // should not happen.
- // TODO: how to handle?
- resultNumber = 3;
- }
- }
- if (longestParseDistance == 0) {
- pos.setIndex(oldPos);
- pos.setErrorIndex(0);
- } else {
- UErrorCode status = U_ZERO_ERROR;
- TimeUnitAmount* tmutamt = new TimeUnitAmount(resultNumber, resultTimeUnit, status);
- if (U_SUCCESS(status)) {
- result.adoptObject(tmutamt);
- pos.setIndex(newPos);
- pos.setErrorIndex(-1);
- } else {
- pos.setIndex(oldPos);
- pos.setErrorIndex(0);
- }
- }
-}
-
-
-void
-TimeUnitFormat::create(const Locale& locale, EStyle style, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return;
- }
- if (style < kFull || style > kAbbreviate) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return;
- }
- fStyle = style;
- fLocale = locale;
- for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
- i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
- i = (TimeUnit::UTimeUnitFields)(i+1)) {
- fTimeUnitToCountToPatterns[i] = NULL;
- }
- //TODO: format() and parseObj() are const member functions,
- //so, can not do lazy initialization in C++.
- //setup has to be done in constructors.
- //and here, the behavior is not consistent with Java.
- //In Java, create an empty instance does not setup locale as
- //default locale. If it followed by setNumberFormat(),
- //in format(), the locale will set up as the locale in fNumberFormat.
- //But in C++, this sets the locale as the default locale.
- setup(status);
-}
-
-void
-TimeUnitFormat::setup(UErrorCode& err) {
- initDataMembers(err);
- readFromCurrentLocale(kFull, gUnitsTag, err);
- checkConsistency(kFull, gUnitsTag, err);
- readFromCurrentLocale(kAbbreviate, gShortUnitsTag, err);
- checkConsistency(kAbbreviate, gShortUnitsTag, err);
-}
-
-
-void
-TimeUnitFormat::initDataMembers(UErrorCode& err){
- if (U_FAILURE(err)) {
- return;
- }
- if (fNumberFormat == NULL) {
- fNumberFormat = NumberFormat::createInstance(fLocale, err);
- }
- delete fPluralRules;
- fPluralRules = PluralRules::forLocale(fLocale, err);
- for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
- i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
- i = (TimeUnit::UTimeUnitFields)(i+1)) {
- deleteHash(fTimeUnitToCountToPatterns[i]);
- fTimeUnitToCountToPatterns[i] = NULL;
- }
-}
-
-
-
-
-void
-TimeUnitFormat::readFromCurrentLocale(EStyle style, const char* key, UErrorCode& err) {
- if (U_FAILURE(err)) {
- return;
- }
- // fill timeUnitToCountToPatterns from resource file
- // err is used to indicate wrong status except missing resource.
- // status is an error code used in resource lookup.
- // status does not affect "err".
- UErrorCode status = U_ZERO_ERROR;
- UResourceBundle *rb, *unitsRes;
- rb = ures_open(NULL, fLocale.getName(), &status);
- unitsRes = ures_getByKey(rb, key, NULL, &status);
- if (U_FAILURE(status)) {
- ures_close(unitsRes);
- ures_close(rb);
- return;
- }
- int32_t size = ures_getSize(unitsRes);
- for ( int32_t index = 0; index < size; ++index) {
- // resource of one time unit
- UResourceBundle* oneTimeUnit = ures_getByIndex(unitsRes, index,
- NULL, &status);
- if (U_SUCCESS(status)) {
- const char* timeUnitName = ures_getKey(oneTimeUnit);
- if (timeUnitName == NULL) {
- ures_close(oneTimeUnit);
- continue;
- }
- UResourceBundle* countsToPatternRB = ures_getByKey(unitsRes,
- timeUnitName,
- NULL, &status);
- if (countsToPatternRB == NULL || U_FAILURE(status)) {
- ures_close(countsToPatternRB);
- ures_close(oneTimeUnit);
- continue;
- }
- TimeUnit::UTimeUnitFields timeUnitField = TimeUnit::UTIMEUNIT_FIELD_COUNT;
- if ( uprv_strcmp(timeUnitName, gTimeUnitYear) == 0 ) {
- timeUnitField = TimeUnit::UTIMEUNIT_YEAR;
- } else if ( uprv_strcmp(timeUnitName, gTimeUnitMonth) == 0 ) {
- timeUnitField = TimeUnit::UTIMEUNIT_MONTH;
- } else if ( uprv_strcmp(timeUnitName, gTimeUnitDay) == 0 ) {
- timeUnitField = TimeUnit::UTIMEUNIT_DAY;
- } else if ( uprv_strcmp(timeUnitName, gTimeUnitHour) == 0 ) {
- timeUnitField = TimeUnit::UTIMEUNIT_HOUR;
- } else if ( uprv_strcmp(timeUnitName, gTimeUnitMinute) == 0 ) {
- timeUnitField = TimeUnit::UTIMEUNIT_MINUTE;
- } else if ( uprv_strcmp(timeUnitName, gTimeUnitSecond) == 0 ) {
- timeUnitField = TimeUnit::UTIMEUNIT_SECOND;
- } else if ( uprv_strcmp(timeUnitName, gTimeUnitWeek) == 0 ) {
- timeUnitField = TimeUnit::UTIMEUNIT_WEEK;
- } else {
- ures_close(countsToPatternRB);
- ures_close(oneTimeUnit);
- continue;
- }
- Hashtable* countToPatterns = fTimeUnitToCountToPatterns[timeUnitField];
- if (countToPatterns == NULL) {
- countToPatterns = initHash(err);
- if (U_FAILURE(err)) {
- ures_close(countsToPatternRB);
- ures_close(oneTimeUnit);
- delete countToPatterns;
- break;
- }
- }
- int32_t count = ures_getSize(countsToPatternRB);
- const UChar* pattern;
- const char* pluralCount;
- int32_t ptLength;
- for ( int32_t pluralIndex = 0; pluralIndex < count; ++pluralIndex) {
- // resource of count to pattern
- pattern = ures_getNextString(countsToPatternRB, &ptLength,
- &pluralCount, &status);
- if (U_FAILURE(status)) {
- continue;
- }
- MessageFormat* messageFormat = new MessageFormat(pattern, fLocale, err);
- if ( U_SUCCESS(err) ) {
- if (fNumberFormat != NULL) {
- messageFormat->setFormat(0, *fNumberFormat);
- }
- MessageFormat** formatters = (MessageFormat**)countToPatterns->get(pluralCount);
- if (formatters == NULL) {
- // formatters = new MessageFormat*[kTotal];
- formatters = (MessageFormat**)uprv_malloc(2*sizeof(MessageFormat*));
- formatters[kFull] = NULL;
- formatters[kAbbreviate] = NULL;
- countToPatterns->put(pluralCount, formatters, err);
- if (U_FAILURE(err)) {
- delete [] formatters;
- }
- }
- if (U_SUCCESS(err)) {
- //delete formatters[style];
- formatters[style] = messageFormat;
- }
- }
- if (U_FAILURE(err)) {
- ures_close(countsToPatternRB);
- ures_close(oneTimeUnit);
- ures_close(unitsRes);
- ures_close(rb);
- delete messageFormat;
- delete countToPatterns;
- return;
- }
- }
- if (fTimeUnitToCountToPatterns[timeUnitField] == NULL) {
- fTimeUnitToCountToPatterns[timeUnitField] = countToPatterns;
- }
- ures_close(countsToPatternRB);
- }
- ures_close(oneTimeUnit);
- }
- ures_close(unitsRes);
- ures_close(rb);
-}
-
-
-void
-TimeUnitFormat::checkConsistency(EStyle style, const char* key, UErrorCode& err) {
- if (U_FAILURE(err)) {
- return;
- }
- // there should be patterns for each plural rule in each time unit.
- // For each time unit,
- // for each plural rule, following is unit pattern fall-back rule:
- // ( for example: "one" hour )
- // look for its unit pattern in its locale tree.
- // if pattern is not found in its own locale, such as de_DE,
- // look for the pattern in its parent, such as de,
- // keep looking till found or till root.
- // if the pattern is not found in root either,
- // fallback to plural count "other",
- // look for the pattern of "other" in the locale tree:
- // "de_DE" to "de" to "root".
- // If not found, fall back to value of
- // static variable DEFAULT_PATTERN_FOR_xxx, such as "{0} h".
- //
- // Following is consistency check to create pattern for each
- // plural rule in each time unit using above fall-back rule.
- //
- StringEnumeration* keywords = fPluralRules->getKeywords(err);
- if (U_SUCCESS(err)) {
- const char* pluralCount;
- while ((pluralCount = keywords->next(NULL, err)) != NULL) {
- if ( U_SUCCESS(err) ) {
- for (int32_t i = 0; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; ++i) {
- // for each time unit,
- // get all the patterns for each plural rule in this locale.
- Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i];
- if ( countToPatterns == NULL ) {
- countToPatterns = initHash(err);
- if (U_FAILURE(err)) {
- delete countToPatterns;
- return;
- }
- fTimeUnitToCountToPatterns[i] = countToPatterns;
- }
- MessageFormat** formatters = (MessageFormat**)countToPatterns->get(pluralCount);
- if( formatters == NULL || formatters[style] == NULL ) {
- // look through parents
- searchInLocaleChain(style, key,
- (TimeUnit::UTimeUnitFields)i,
- pluralCount, pluralCount,
- countToPatterns, err);
- }
- }
- }
- }
- }
- delete keywords;
-}
-
-
-
-// srcPluralCount is the original plural count on which the pattern is
-// searched for.
-// searchPluralCount is the fallback plural count.
-// For example, to search for pattern for ""one" hour",
-// "one" is the srcPluralCount,
-// if the pattern is not found even in root, fallback to
-// using patterns of plural count "other",
-// then, "other" is the searchPluralCount.
-void
-TimeUnitFormat::searchInLocaleChain(EStyle style, const char* key,
- TimeUnit::UTimeUnitFields srcTimeUnitField,
- const char* srcPluralCount,
- const char* searchPluralCount,
- Hashtable* countToPatterns,
- UErrorCode& err) {
- if (U_FAILURE(err)) {
- return;
- }
- UErrorCode status = U_ZERO_ERROR;
- const char *locName = fLocale.getName();
- char parentLocale[ULOC_FULLNAME_CAPACITY];
- uprv_strcpy(parentLocale, locName);
- int32_t locNameLen;
- while ((locNameLen = uloc_getParent(parentLocale, parentLocale,
- ULOC_FULLNAME_CAPACITY, &status)) >= 0){
- // look for pattern for srcPluralCount in locale tree
- UResourceBundle *rb, *unitsRes, *countsToPatternRB;
- rb = ures_open(NULL, parentLocale, &status);
- unitsRes = ures_getByKey(rb, key, NULL, &status);
- const char* timeUnitName = getTimeUnitName(srcTimeUnitField, status);
- countsToPatternRB = ures_getByKey(unitsRes, timeUnitName, NULL, &status);
- const UChar* pattern;
- int32_t ptLength;
- pattern = ures_getStringByKeyWithFallback(countsToPatternRB, searchPluralCount, &ptLength, &status);
- if (U_SUCCESS(status)) {
- //found
- MessageFormat* messageFormat = new MessageFormat(pattern, fLocale, err);
- if (U_SUCCESS(err)) {
- if (fNumberFormat != NULL) {
- messageFormat->setFormat(0, *fNumberFormat);
- }
- MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount);
- if (formatters == NULL) {
- //formatters = new MessageFormat*[kTotal];
- formatters = (MessageFormat**)uprv_malloc(2*sizeof(MessageFormat*));
- formatters[kFull] = NULL;
- formatters[kAbbreviate] = NULL;
- countToPatterns->put(srcPluralCount, formatters, err);
- if (U_FAILURE(err)) {
- delete [] formatters;
- delete messageFormat;
- }
- }
- if (U_SUCCESS(err)) {
- //delete formatters[style];
- formatters[style] = messageFormat;
- }
- } else {
- delete messageFormat;
- }
- ures_close(countsToPatternRB);
- ures_close(unitsRes);
- ures_close(rb);
- return;
- }
- ures_close(countsToPatternRB);
- ures_close(unitsRes);
- ures_close(rb);
- if ( locNameLen ==0 ) {
- break;
- }
- }
- // if not found the pattern for this plural count at all,
- // fall-back to plural count "other"
- if ( uprv_strcmp(searchPluralCount, gPluralCountOther) == 0 ) {
- // set default fall back the same as the resource in root
- MessageFormat* messageFormat = NULL;
- if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_SECOND ) {
- messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_SECOND, fLocale, err);
- } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_MINUTE ) {
- messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_MINUTE, fLocale, err);
- } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_HOUR ) {
- messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_HOUR, fLocale, err);
- } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_WEEK ) {
- messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_WEEK, fLocale, err);
- } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_DAY ) {
- messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_DAY, fLocale, err);
- } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_MONTH ) {
- messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_MONTH, fLocale, err);
- } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_YEAR ) {
- messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_YEAR, fLocale, err);
- }
- if (U_SUCCESS(err)) {
- if (fNumberFormat != NULL && messageFormat != NULL) {
- messageFormat->setFormat(0, *fNumberFormat);
- }
- MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount);
- if (formatters == NULL) {
- //formatters = new MessageFormat*[kTotal];
- formatters = (MessageFormat**)uprv_malloc(2*sizeof(MessageFormat*));
- formatters[kFull] = NULL;
- formatters[kAbbreviate] = NULL;
- countToPatterns->put(srcPluralCount, formatters, err);
- if (U_FAILURE(err)) {
- delete [] formatters;
- delete messageFormat;
- }
- }
- if (U_SUCCESS(err)) {
- //delete formatters[style];
- formatters[style] = messageFormat;
- }
- } else {
- delete messageFormat;
- }
- } else {
- // fall back to rule "other", and search in parents
- searchInLocaleChain(style, key, srcTimeUnitField, srcPluralCount,
- gPluralCountOther, countToPatterns, err);
- }
-}
-
-void
-TimeUnitFormat::setLocale(const Locale& locale, UErrorCode& status) {
- if (U_SUCCESS(status) && fLocale != locale) {
- fLocale = locale;
- setup(status);
- }
-}
-
-
-void
-TimeUnitFormat::setNumberFormat(const NumberFormat& format, UErrorCode& status){
- if (U_FAILURE(status) || fNumberFormat && format == *fNumberFormat) {
- return;
- }
- delete fNumberFormat;
- fNumberFormat = (NumberFormat*)format.clone();
- // reset the number formatter in the fTimeUnitToCountToPatterns map
- for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
- i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
- i = (TimeUnit::UTimeUnitFields)(i+1)) {
- int32_t pos = -1;
- const UHashElement* elem = NULL;
- while ((elem = fTimeUnitToCountToPatterns[i]->nextElement(pos)) != NULL){
- const UHashTok keyTok = elem->value;
- MessageFormat** pattern = (MessageFormat**)keyTok.pointer;
- pattern[kFull]->setFormat(0, format);
- pattern[kAbbreviate]->setFormat(0, format);
- }
- }
-}
-
-
-void
-TimeUnitFormat::deleteHash(Hashtable* htable) {
- int32_t pos = -1;
- const UHashElement* element = NULL;
- if ( htable ) {
- while ( (element = htable->nextElement(pos)) != NULL ) {
- const UHashTok valueTok = element->value;
- const MessageFormat** value = (const MessageFormat**)valueTok.pointer;
- delete value[kFull];
- delete value[kAbbreviate];
- //delete[] value;
- uprv_free(value);
- }
- }
- delete htable;
-}
-
-
-void
-TimeUnitFormat::copyHash(const Hashtable* source, Hashtable* target, UErrorCode& status) {
- if ( U_FAILURE(status) ) {
- return;
- }
- int32_t pos = -1;
- const UHashElement* element = NULL;
- if ( source ) {
- while ( (element = source->nextElement(pos)) != NULL ) {
- const UHashTok keyTok = element->key;
- const UnicodeString* key = (UnicodeString*)keyTok.pointer;
- const UHashTok valueTok = element->value;
- const MessageFormat** value = (const MessageFormat**)valueTok.pointer;
- //MessageFormat** newVal = new MessageFormat*[kTotal];
- MessageFormat** newVal = (MessageFormat**)uprv_malloc(2*sizeof(MessageFormat*));
- newVal[0] = (MessageFormat*)value[0]->clone();
- newVal[1] = (MessageFormat*)value[1]->clone();
- target->put(UnicodeString(*key), newVal, status);
- if ( U_FAILURE(status) ) {
- delete newVal[0];
- delete newVal[1];
- delete [] newVal;
- return;
- }
- }
- }
-}
-
-
-U_CDECL_BEGIN
-
-/**
- * set hash table value comparator
- *
- * @param val1 one value in comparison
- * @param val2 the other value in comparison
- * @return TRUE if 2 values are the same, FALSE otherwise
- */
-static UBool U_CALLCONV hashTableValueComparator(UHashTok val1, UHashTok val2);
-
-U_CDECL_END
-
-UBool
-U_CALLCONV hashTableValueComparator(UHashTok val1, UHashTok val2) {
- const MessageFormat** pattern1 = (const MessageFormat**)val1.pointer;
- const MessageFormat** pattern2 = (const MessageFormat**)val2.pointer;
- return *pattern1[0] == *pattern2[0] && *pattern1[1] == *pattern2[1];
-}
-
-
-Hashtable*
-TimeUnitFormat::initHash(UErrorCode& status) {
- if ( U_FAILURE(status) ) {
- return NULL;
- }
- Hashtable* hTable;
- if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
- hTable->setValueCompartor(hashTableValueComparator);
- return hTable;
-}
-
-
-const char*
-TimeUnitFormat::getTimeUnitName(TimeUnit::UTimeUnitFields unitField,
- UErrorCode& status) {
- if (U_FAILURE(status)) {
- return NULL;
- }
- switch (unitField) {
- case TimeUnit::UTIMEUNIT_YEAR:
- return gTimeUnitYear;
- case TimeUnit::UTIMEUNIT_MONTH:
- return gTimeUnitMonth;
- case TimeUnit::UTIMEUNIT_DAY:
- return gTimeUnitDay;
- case TimeUnit::UTIMEUNIT_WEEK:
- return gTimeUnitWeek;
- case TimeUnit::UTIMEUNIT_HOUR:
- return gTimeUnitHour;
- case TimeUnit::UTIMEUNIT_MINUTE:
- return gTimeUnitMinute;
- case TimeUnit::UTIMEUNIT_SECOND:
- return gTimeUnitSecond;
- default:
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return NULL;
- }
-}
-
-U_NAMESPACE_END
-
-#endif
+/*
+ *******************************************************************************
+ * Copyright (C) 2008-2009, Google, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ *******************************************************************************
+ */
+
+
+#include "unicode/tmutfmt.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "cmemory.h"
+#include "cstring.h"
+#include "hash.h"
+#include "uresimp.h"
+#include "unicode/msgfmt.h"
+
+#define LEFT_CURLY_BRACKET ((UChar)0x007B)
+#define RIGHT_CURLY_BRACKET ((UChar)0x007D)
+#define SPACE ((UChar)0x0020)
+#define DIGIT_ZERO ((UChar)0x0030)
+#define LOW_S ((UChar)0x0073)
+#define LOW_M ((UChar)0x006D)
+#define LOW_I ((UChar)0x0069)
+#define LOW_N ((UChar)0x006E)
+#define LOW_H ((UChar)0x0068)
+#define LOW_W ((UChar)0x0077)
+#define LOW_D ((UChar)0x0064)
+#define LOW_Y ((UChar)0x0079)
+#define LOW_Z ((UChar)0x007A)
+#define LOW_E ((UChar)0x0065)
+#define LOW_R ((UChar)0x0072)
+#define LOW_O ((UChar)0x006F)
+#define LOW_N ((UChar)0x006E)
+#define LOW_T ((UChar)0x0074)
+
+
+//TODO: define in compile time
+//#define TMUTFMT_DEBUG 1
+
+#ifdef TMUTFMT_DEBUG
+#include <iostream>
+#endif
+
+U_NAMESPACE_BEGIN
+
+
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeUnitFormat)
+
+static const char gUnitsTag[] = "units";
+static const char gShortUnitsTag[] = "unitsShort";
+static const char gTimeUnitYear[] = "year";
+static const char gTimeUnitMonth[] = "month";
+static const char gTimeUnitDay[] = "day";
+static const char gTimeUnitWeek[] = "week";
+static const char gTimeUnitHour[] = "hour";
+static const char gTimeUnitMinute[] = "minute";
+static const char gTimeUnitSecond[] = "second";
+static const char gPluralCountOther[] = "other";
+
+static const UChar DEFAULT_PATTERN_FOR_SECOND[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_S, 0};
+static const UChar DEFAULT_PATTERN_FOR_MINUTE[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_M, LOW_I, LOW_N, 0};
+static const UChar DEFAULT_PATTERN_FOR_HOUR[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_H, 0};
+static const UChar DEFAULT_PATTERN_FOR_WEEK[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_W, 0};
+static const UChar DEFAULT_PATTERN_FOR_DAY[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_D, 0};
+static const UChar DEFAULT_PATTERN_FOR_MONTH[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_M, 0};
+static const UChar DEFAULT_PATTERN_FOR_YEAR[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, LOW_Y, 0};
+
+static const UChar PLURAL_COUNT_ZERO[] = {LOW_Z, LOW_E, LOW_R, LOW_O, 0};
+static const UChar PLURAL_COUNT_ONE[] = {LOW_O, LOW_N, LOW_E, 0};
+static const UChar PLURAL_COUNT_TWO[] = {LOW_T, LOW_W, LOW_O, 0};
+
+
+TimeUnitFormat::TimeUnitFormat(UErrorCode& status)
+: fNumberFormat(NULL),
+ fPluralRules(NULL) {
+ create(Locale::getDefault(), kFull, status);
+}
+
+
+TimeUnitFormat::TimeUnitFormat(const Locale& locale, UErrorCode& status)
+: fNumberFormat(NULL),
+ fPluralRules(NULL) {
+ create(locale, kFull, status);
+}
+
+
+TimeUnitFormat::TimeUnitFormat(const Locale& locale, EStyle style, UErrorCode& status)
+: fNumberFormat(NULL),
+ fPluralRules(NULL) {
+ create(locale, style, status);
+}
+
+
+TimeUnitFormat::TimeUnitFormat(const TimeUnitFormat& other)
+: MeasureFormat(other),
+ fNumberFormat(NULL),
+ fPluralRules(NULL),
+ fStyle(kFull)
+{
+ for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
+ i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
+ i = (TimeUnit::UTimeUnitFields)(i+1)) {
+ fTimeUnitToCountToPatterns[i] = NULL;
+ }
+ *this = other;
+}
+
+
+TimeUnitFormat::~TimeUnitFormat() {
+ delete fNumberFormat;
+ fNumberFormat = NULL;
+ for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
+ i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
+ i = (TimeUnit::UTimeUnitFields)(i+1)) {
+ deleteHash(fTimeUnitToCountToPatterns[i]);
+ fTimeUnitToCountToPatterns[i] = NULL;
+ }
+ delete fPluralRules;
+ fPluralRules = NULL;
+}
+
+
+Format*
+TimeUnitFormat::clone(void) const {
+ return new TimeUnitFormat(*this);
+}
+
+
+TimeUnitFormat&
+TimeUnitFormat::operator=(const TimeUnitFormat& other) {
+ if (this == &other) {
+ return *this;
+ }
+ delete fNumberFormat;
+ for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
+ i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
+ i = (TimeUnit::UTimeUnitFields)(i+1)) {
+ deleteHash(fTimeUnitToCountToPatterns[i]);
+ fTimeUnitToCountToPatterns[i] = NULL;
+ }
+ delete fPluralRules;
+ if (other.fNumberFormat) {
+ fNumberFormat = (NumberFormat*)other.fNumberFormat->clone();
+ } else {
+ fNumberFormat = NULL;
+ }
+ fLocale = other.fLocale;
+ for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
+ i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
+ i = (TimeUnit::UTimeUnitFields)(i+1)) {
+ UErrorCode status = U_ZERO_ERROR;
+ fTimeUnitToCountToPatterns[i] = initHash(status);
+ if (U_SUCCESS(status)) {
+ copyHash(other.fTimeUnitToCountToPatterns[i], fTimeUnitToCountToPatterns[i], status);
+ } else {
+ delete fTimeUnitToCountToPatterns[i];
+ fTimeUnitToCountToPatterns[i] = NULL;
+ }
+ }
+ if (other.fPluralRules) {
+ fPluralRules = (PluralRules*)other.fPluralRules->clone();
+ } else {
+ fPluralRules = NULL;
+ }
+ fStyle = other.fStyle;
+ return *this;
+}
+
+
+UBool
+TimeUnitFormat::operator==(const Format& other) const {
+ if (other.getDynamicClassID() == TimeUnitFormat::getStaticClassID()) {
+ TimeUnitFormat* fmt = (TimeUnitFormat*)&other;
+ UBool ret = ( (fNumberFormat && fmt->fNumberFormat &&
+ *fNumberFormat == *fmt->fNumberFormat ||
+ fNumberFormat == fmt->fNumberFormat ) &&
+ fLocale == fmt->fLocale &&
+ (fPluralRules && fmt->fPluralRules &&
+ *fPluralRules == *fmt->fPluralRules ||
+ fPluralRules == fmt->fPluralRules) &&
+ fStyle == fmt->fStyle);
+ if (ret) {
+ for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
+ i < TimeUnit::UTIMEUNIT_FIELD_COUNT && ret;
+ i = (TimeUnit::UTimeUnitFields)(i+1)) {
+ ret = fTimeUnitToCountToPatterns[i]->equals(*(fmt->fTimeUnitToCountToPatterns[i]));
+ }
+ }
+ return ret;
+ }
+ return false;
+}
+
+
+UnicodeString&
+TimeUnitFormat::format(const Formattable& obj, UnicodeString& toAppendTo,
+ FieldPosition& pos, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return toAppendTo;
+ }
+ if (obj.getType() == Formattable::kObject) {
+ const UObject* formatObj = obj.getObject();
+ if (formatObj->getDynamicClassID() == TimeUnitAmount::getStaticClassID()){
+ TimeUnitAmount* amount = (TimeUnitAmount*)formatObj;
+ Hashtable* countToPattern = fTimeUnitToCountToPatterns[amount->getTimeUnitField()];
+ double number;
+ const Formattable& amtNumber = amount->getNumber();
+ if (amtNumber.getType() == Formattable::kDouble) {
+ number = amtNumber.getDouble();
+ } else if (amtNumber.getType() == Formattable::kLong) {
+ number = amtNumber.getLong();
+ } else {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return toAppendTo;
+ }
+ UnicodeString count = fPluralRules->select(number);
+#ifdef TMUTFMT_DEBUG
+ char result[1000];
+ count.extract(0, count.length(), result, "UTF-8");
+ std::cout << "number: " << number << "; format plural count: " << result << "\n";
+#endif
+ MessageFormat* pattern = ((MessageFormat**)countToPattern->get(count))[fStyle];
+ Formattable formattable[1];
+ formattable[0].setDouble(number);
+ return pattern->format(formattable, 1, toAppendTo, pos, status);
+ }
+ }
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return toAppendTo;
+}
+
+
+void
+TimeUnitFormat::parseObject(const UnicodeString& source,
+ Formattable& result,
+ ParsePosition& pos) const {
+ double resultNumber = -1;
+ UBool withNumberFormat = false;
+ TimeUnit::UTimeUnitFields resultTimeUnit = TimeUnit::UTIMEUNIT_FIELD_COUNT;
+ int32_t oldPos = pos.getIndex();
+ int32_t newPos = -1;
+ int32_t longestParseDistance = 0;
+ UnicodeString* countOfLongestMatch = NULL;
+#ifdef TMUTFMT_DEBUG
+ char res[1000];
+ source.extract(0, source.length(), res, "UTF-8");
+ std::cout << "parse source: " << res << "\n";
+#endif
+ // parse by iterating through all available patterns
+ // and looking for the longest match.
+ for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
+ i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
+ i = (TimeUnit::UTimeUnitFields)(i+1)) {
+ Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i];
+ int32_t elemPos = -1;
+ const UHashElement* elem = NULL;
+ while ((elem = countToPatterns->nextElement(elemPos)) != NULL){
+ const UHashTok keyTok = elem->key;
+ UnicodeString* count = (UnicodeString*)keyTok.pointer;
+#ifdef TMUTFMT_DEBUG
+ count->extract(0, count->length(), res, "UTF-8");
+ std::cout << "parse plural count: " << res << "\n";
+#endif
+ const UHashTok valueTok = elem->value;
+ // the value is a pair of MessageFormat*
+ MessageFormat** patterns = (MessageFormat**)valueTok.pointer;
+ for (EStyle style = kFull; style < kTotal; style = (EStyle)(style + 1)) {
+ MessageFormat* pattern = patterns[style];
+ pos.setErrorIndex(-1);
+ pos.setIndex(oldPos);
+ // see if we can parse
+ Formattable parsed;
+ pattern->parseObject(source, parsed, pos);
+ if (pos.getErrorIndex() != -1 || pos.getIndex() == oldPos) {
+ continue;
+ }
+ #ifdef TMUTFMT_DEBUG
+ std::cout << "parsed.getType: " << parsed.getType() << "\n";
+ #endif
+ double tmpNumber = 0;
+ if (pattern->getArgTypeCount() != 0) {
+ // pattern with Number as beginning, such as "{0} d".
+ // check to make sure that the timeUnit is consistent
+ Formattable& temp = parsed[0];
+ if (temp.getType() == Formattable::kDouble) {
+ tmpNumber = temp.getDouble();
+ } else if (temp.getType() == Formattable::kLong) {
+ tmpNumber = temp.getLong();
+ } else {
+ continue;
+ }
+ UnicodeString select = fPluralRules->select(tmpNumber);
+ #ifdef TMUTFMT_DEBUG
+ select.extract(0, select.length(), res, "UTF-8");
+ std::cout << "parse plural select count: " << res << "\n";
+ #endif
+ if (*count != select) {
+ continue;
+ }
+ }
+ int32_t parseDistance = pos.getIndex() - oldPos;
+ if (parseDistance > longestParseDistance) {
+ if (pattern->getArgTypeCount() != 0) {
+ resultNumber = tmpNumber;
+ withNumberFormat = true;
+ } else {
+ withNumberFormat = false;
+ }
+ resultTimeUnit = i;
+ newPos = pos.getIndex();
+ longestParseDistance = parseDistance;
+ countOfLongestMatch = count;
+ }
+ }
+ }
+ }
+ /* After find the longest match, parse the number.
+ * Result number could be null for the pattern without number pattern.
+ * such as unit pattern in Arabic.
+ * When result number is null, use plural rule to set the number.
+ */
+ if (withNumberFormat == false && longestParseDistance != 0) {
+ // set the number using plurrual count
+ if ( *countOfLongestMatch == PLURAL_COUNT_ZERO ) {
+ resultNumber = 0;
+ } else if ( *countOfLongestMatch == PLURAL_COUNT_ONE ) {
+ resultNumber = 1;
+ } else if ( *countOfLongestMatch == PLURAL_COUNT_TWO ) {
+ resultNumber = 2;
+ } else {
+ // should not happen.
+ // TODO: how to handle?
+ resultNumber = 3;
+ }
+ }
+ if (longestParseDistance == 0) {
+ pos.setIndex(oldPos);
+ pos.setErrorIndex(0);
+ } else {
+ UErrorCode status = U_ZERO_ERROR;
+ TimeUnitAmount* tmutamt = new TimeUnitAmount(resultNumber, resultTimeUnit, status);
+ if (U_SUCCESS(status)) {
+ result.adoptObject(tmutamt);
+ pos.setIndex(newPos);
+ pos.setErrorIndex(-1);
+ } else {
+ pos.setIndex(oldPos);
+ pos.setErrorIndex(0);
+ }
+ }
+}
+
+
+void
+TimeUnitFormat::create(const Locale& locale, EStyle style, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (style < kFull || style > kAbbreviate) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ fStyle = style;
+ fLocale = locale;
+ for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
+ i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
+ i = (TimeUnit::UTimeUnitFields)(i+1)) {
+ fTimeUnitToCountToPatterns[i] = NULL;
+ }
+ //TODO: format() and parseObj() are const member functions,
+ //so, can not do lazy initialization in C++.
+ //setup has to be done in constructors.
+ //and here, the behavior is not consistent with Java.
+ //In Java, create an empty instance does not setup locale as
+ //default locale. If it followed by setNumberFormat(),
+ //in format(), the locale will set up as the locale in fNumberFormat.
+ //But in C++, this sets the locale as the default locale.
+ setup(status);
+}
+
+void
+TimeUnitFormat::setup(UErrorCode& err) {
+ initDataMembers(err);
+ readFromCurrentLocale(kFull, gUnitsTag, err);
+ checkConsistency(kFull, gUnitsTag, err);
+ readFromCurrentLocale(kAbbreviate, gShortUnitsTag, err);
+ checkConsistency(kAbbreviate, gShortUnitsTag, err);
+}
+
+
+void
+TimeUnitFormat::initDataMembers(UErrorCode& err){
+ if (U_FAILURE(err)) {
+ return;
+ }
+ if (fNumberFormat == NULL) {
+ fNumberFormat = NumberFormat::createInstance(fLocale, err);
+ }
+ delete fPluralRules;
+ fPluralRules = PluralRules::forLocale(fLocale, err);
+ for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
+ i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
+ i = (TimeUnit::UTimeUnitFields)(i+1)) {
+ deleteHash(fTimeUnitToCountToPatterns[i]);
+ fTimeUnitToCountToPatterns[i] = NULL;
+ }
+}
+
+
+
+
+void
+TimeUnitFormat::readFromCurrentLocale(EStyle style, const char* key, UErrorCode& err) {
+ if (U_FAILURE(err)) {
+ return;
+ }
+ // fill timeUnitToCountToPatterns from resource file
+ // err is used to indicate wrong status except missing resource.
+ // status is an error code used in resource lookup.
+ // status does not affect "err".
+ UErrorCode status = U_ZERO_ERROR;
+ UResourceBundle *rb, *unitsRes;
+ rb = ures_open(NULL, fLocale.getName(), &status);
+ unitsRes = ures_getByKey(rb, key, NULL, &status);
+ if (U_FAILURE(status)) {
+ ures_close(unitsRes);
+ ures_close(rb);
+ return;
+ }
+ int32_t size = ures_getSize(unitsRes);
+ for ( int32_t index = 0; index < size; ++index) {
+ // resource of one time unit
+ UResourceBundle* oneTimeUnit = ures_getByIndex(unitsRes, index,
+ NULL, &status);
+ if (U_SUCCESS(status)) {
+ const char* timeUnitName = ures_getKey(oneTimeUnit);
+ if (timeUnitName == NULL) {
+ ures_close(oneTimeUnit);
+ continue;
+ }
+ UResourceBundle* countsToPatternRB = ures_getByKey(unitsRes,
+ timeUnitName,
+ NULL, &status);
+ if (countsToPatternRB == NULL || U_FAILURE(status)) {
+ ures_close(countsToPatternRB);
+ ures_close(oneTimeUnit);
+ continue;
+ }
+ TimeUnit::UTimeUnitFields timeUnitField = TimeUnit::UTIMEUNIT_FIELD_COUNT;
+ if ( uprv_strcmp(timeUnitName, gTimeUnitYear) == 0 ) {
+ timeUnitField = TimeUnit::UTIMEUNIT_YEAR;
+ } else if ( uprv_strcmp(timeUnitName, gTimeUnitMonth) == 0 ) {
+ timeUnitField = TimeUnit::UTIMEUNIT_MONTH;
+ } else if ( uprv_strcmp(timeUnitName, gTimeUnitDay) == 0 ) {
+ timeUnitField = TimeUnit::UTIMEUNIT_DAY;
+ } else if ( uprv_strcmp(timeUnitName, gTimeUnitHour) == 0 ) {
+ timeUnitField = TimeUnit::UTIMEUNIT_HOUR;
+ } else if ( uprv_strcmp(timeUnitName, gTimeUnitMinute) == 0 ) {
+ timeUnitField = TimeUnit::UTIMEUNIT_MINUTE;
+ } else if ( uprv_strcmp(timeUnitName, gTimeUnitSecond) == 0 ) {
+ timeUnitField = TimeUnit::UTIMEUNIT_SECOND;
+ } else if ( uprv_strcmp(timeUnitName, gTimeUnitWeek) == 0 ) {
+ timeUnitField = TimeUnit::UTIMEUNIT_WEEK;
+ } else {
+ ures_close(countsToPatternRB);
+ ures_close(oneTimeUnit);
+ continue;
+ }
+ Hashtable* countToPatterns = fTimeUnitToCountToPatterns[timeUnitField];
+ if (countToPatterns == NULL) {
+ countToPatterns = initHash(err);
+ if (U_FAILURE(err)) {
+ ures_close(countsToPatternRB);
+ ures_close(oneTimeUnit);
+ delete countToPatterns;
+ break;
+ }
+ }
+ int32_t count = ures_getSize(countsToPatternRB);
+ const UChar* pattern;
+ const char* pluralCount;
+ int32_t ptLength;
+ for ( int32_t pluralIndex = 0; pluralIndex < count; ++pluralIndex) {
+ // resource of count to pattern
+ pattern = ures_getNextString(countsToPatternRB, &ptLength,
+ &pluralCount, &status);
+ if (U_FAILURE(status)) {
+ continue;
+ }
+ MessageFormat* messageFormat = new MessageFormat(pattern, fLocale, err);
+ if ( U_SUCCESS(err) ) {
+ if (fNumberFormat != NULL) {
+ messageFormat->setFormat(0, *fNumberFormat);
+ }
+ MessageFormat** formatters = (MessageFormat**)countToPatterns->get(pluralCount);
+ if (formatters == NULL) {
+ // formatters = new MessageFormat*[kTotal];
+ formatters = (MessageFormat**)uprv_malloc(2*sizeof(MessageFormat*));
+ formatters[kFull] = NULL;
+ formatters[kAbbreviate] = NULL;
+ countToPatterns->put(pluralCount, formatters, err);
+ if (U_FAILURE(err)) {
+ delete [] formatters;
+ }
+ }
+ if (U_SUCCESS(err)) {
+ //delete formatters[style];
+ formatters[style] = messageFormat;
+ }
+ }
+ if (U_FAILURE(err)) {
+ ures_close(countsToPatternRB);
+ ures_close(oneTimeUnit);
+ ures_close(unitsRes);
+ ures_close(rb);
+ delete messageFormat;
+ delete countToPatterns;
+ return;
+ }
+ }
+ if (fTimeUnitToCountToPatterns[timeUnitField] == NULL) {
+ fTimeUnitToCountToPatterns[timeUnitField] = countToPatterns;
+ }
+ ures_close(countsToPatternRB);
+ }
+ ures_close(oneTimeUnit);
+ }
+ ures_close(unitsRes);
+ ures_close(rb);
+}
+
+
+void
+TimeUnitFormat::checkConsistency(EStyle style, const char* key, UErrorCode& err) {
+ if (U_FAILURE(err)) {
+ return;
+ }
+ // there should be patterns for each plural rule in each time unit.
+ // For each time unit,
+ // for each plural rule, following is unit pattern fall-back rule:
+ // ( for example: "one" hour )
+ // look for its unit pattern in its locale tree.
+ // if pattern is not found in its own locale, such as de_DE,
+ // look for the pattern in its parent, such as de,
+ // keep looking till found or till root.
+ // if the pattern is not found in root either,
+ // fallback to plural count "other",
+ // look for the pattern of "other" in the locale tree:
+ // "de_DE" to "de" to "root".
+ // If not found, fall back to value of
+ // static variable DEFAULT_PATTERN_FOR_xxx, such as "{0} h".
+ //
+ // Following is consistency check to create pattern for each
+ // plural rule in each time unit using above fall-back rule.
+ //
+ StringEnumeration* keywords = fPluralRules->getKeywords(err);
+ if (U_SUCCESS(err)) {
+ const char* pluralCount;
+ while ((pluralCount = keywords->next(NULL, err)) != NULL) {
+ if ( U_SUCCESS(err) ) {
+ for (int32_t i = 0; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; ++i) {
+ // for each time unit,
+ // get all the patterns for each plural rule in this locale.
+ Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i];
+ if ( countToPatterns == NULL ) {
+ countToPatterns = initHash(err);
+ if (U_FAILURE(err)) {
+ delete countToPatterns;
+ return;
+ }
+ fTimeUnitToCountToPatterns[i] = countToPatterns;
+ }
+ MessageFormat** formatters = (MessageFormat**)countToPatterns->get(pluralCount);
+ if( formatters == NULL || formatters[style] == NULL ) {
+ // look through parents
+ searchInLocaleChain(style, key,
+ (TimeUnit::UTimeUnitFields)i,
+ pluralCount, pluralCount,
+ countToPatterns, err);
+ }
+ }
+ }
+ }
+ }
+ delete keywords;
+}
+
+
+
+// srcPluralCount is the original plural count on which the pattern is
+// searched for.
+// searchPluralCount is the fallback plural count.
+// For example, to search for pattern for ""one" hour",
+// "one" is the srcPluralCount,
+// if the pattern is not found even in root, fallback to
+// using patterns of plural count "other",
+// then, "other" is the searchPluralCount.
+void
+TimeUnitFormat::searchInLocaleChain(EStyle style, const char* key,
+ TimeUnit::UTimeUnitFields srcTimeUnitField,
+ const char* srcPluralCount,
+ const char* searchPluralCount,
+ Hashtable* countToPatterns,
+ UErrorCode& err) {
+ if (U_FAILURE(err)) {
+ return;
+ }
+ UErrorCode status = U_ZERO_ERROR;
+ const char *locName = fLocale.getName();
+ char parentLocale[ULOC_FULLNAME_CAPACITY];
+ uprv_strcpy(parentLocale, locName);
+ int32_t locNameLen;
+ while ((locNameLen = uloc_getParent(parentLocale, parentLocale,
+ ULOC_FULLNAME_CAPACITY, &status)) >= 0){
+ // look for pattern for srcPluralCount in locale tree
+ UResourceBundle *rb, *unitsRes, *countsToPatternRB;
+ rb = ures_open(NULL, parentLocale, &status);
+ unitsRes = ures_getByKey(rb, key, NULL, &status);
+ const char* timeUnitName = getTimeUnitName(srcTimeUnitField, status);
+ countsToPatternRB = ures_getByKey(unitsRes, timeUnitName, NULL, &status);
+ const UChar* pattern;
+ int32_t ptLength;
+ pattern = ures_getStringByKeyWithFallback(countsToPatternRB, searchPluralCount, &ptLength, &status);
+ if (U_SUCCESS(status)) {
+ //found
+ MessageFormat* messageFormat = new MessageFormat(pattern, fLocale, err);
+ if (U_SUCCESS(err)) {
+ if (fNumberFormat != NULL) {
+ messageFormat->setFormat(0, *fNumberFormat);
+ }
+ MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount);
+ if (formatters == NULL) {
+ //formatters = new MessageFormat*[kTotal];
+ formatters = (MessageFormat**)uprv_malloc(2*sizeof(MessageFormat*));
+ formatters[kFull] = NULL;
+ formatters[kAbbreviate] = NULL;
+ countToPatterns->put(srcPluralCount, formatters, err);
+ if (U_FAILURE(err)) {
+ delete [] formatters;
+ delete messageFormat;
+ }
+ }
+ if (U_SUCCESS(err)) {
+ //delete formatters[style];
+ formatters[style] = messageFormat;
+ }
+ } else {
+ delete messageFormat;
+ }
+ ures_close(countsToPatternRB);
+ ures_close(unitsRes);
+ ures_close(rb);
+ return;
+ }
+ ures_close(countsToPatternRB);
+ ures_close(unitsRes);
+ ures_close(rb);
+ if ( locNameLen ==0 ) {
+ break;
+ }
+ }
+ // if not found the pattern for this plural count at all,
+ // fall-back to plural count "other"
+ if ( uprv_strcmp(searchPluralCount, gPluralCountOther) == 0 ) {
+ // set default fall back the same as the resource in root
+ MessageFormat* messageFormat = NULL;
+ if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_SECOND ) {
+ messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_SECOND, fLocale, err);
+ } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_MINUTE ) {
+ messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_MINUTE, fLocale, err);
+ } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_HOUR ) {
+ messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_HOUR, fLocale, err);
+ } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_WEEK ) {
+ messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_WEEK, fLocale, err);
+ } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_DAY ) {
+ messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_DAY, fLocale, err);
+ } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_MONTH ) {
+ messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_MONTH, fLocale, err);
+ } else if ( srcTimeUnitField == TimeUnit::UTIMEUNIT_YEAR ) {
+ messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_YEAR, fLocale, err);
+ }
+ if (U_SUCCESS(err)) {
+ if (fNumberFormat != NULL && messageFormat != NULL) {
+ messageFormat->setFormat(0, *fNumberFormat);
+ }
+ MessageFormat** formatters = (MessageFormat**)countToPatterns->get(srcPluralCount);
+ if (formatters == NULL) {
+ //formatters = new MessageFormat*[kTotal];
+ formatters = (MessageFormat**)uprv_malloc(2*sizeof(MessageFormat*));
+ formatters[kFull] = NULL;
+ formatters[kAbbreviate] = NULL;
+ countToPatterns->put(srcPluralCount, formatters, err);
+ if (U_FAILURE(err)) {
+ delete [] formatters;
+ delete messageFormat;
+ }
+ }
+ if (U_SUCCESS(err)) {
+ //delete formatters[style];
+ formatters[style] = messageFormat;
+ }
+ } else {
+ delete messageFormat;
+ }
+ } else {
+ // fall back to rule "other", and search in parents
+ searchInLocaleChain(style, key, srcTimeUnitField, srcPluralCount,
+ gPluralCountOther, countToPatterns, err);
+ }
+}
+
+void
+TimeUnitFormat::setLocale(const Locale& locale, UErrorCode& status) {
+ if (U_SUCCESS(status) && fLocale != locale) {
+ fLocale = locale;
+ setup(status);
+ }
+}
+
+
+void
+TimeUnitFormat::setNumberFormat(const NumberFormat& format, UErrorCode& status){
+ if (U_FAILURE(status) || fNumberFormat && format == *fNumberFormat) {
+ return;
+ }
+ delete fNumberFormat;
+ fNumberFormat = (NumberFormat*)format.clone();
+ // reset the number formatter in the fTimeUnitToCountToPatterns map
+ for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
+ i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
+ i = (TimeUnit::UTimeUnitFields)(i+1)) {
+ int32_t pos = -1;
+ const UHashElement* elem = NULL;
+ while ((elem = fTimeUnitToCountToPatterns[i]->nextElement(pos)) != NULL){
+ const UHashTok keyTok = elem->value;
+ MessageFormat** pattern = (MessageFormat**)keyTok.pointer;
+ pattern[kFull]->setFormat(0, format);
+ pattern[kAbbreviate]->setFormat(0, format);
+ }
+ }
+}
+
+
+void
+TimeUnitFormat::deleteHash(Hashtable* htable) {
+ int32_t pos = -1;
+ const UHashElement* element = NULL;
+ if ( htable ) {
+ while ( (element = htable->nextElement(pos)) != NULL ) {
+ const UHashTok valueTok = element->value;
+ const MessageFormat** value = (const MessageFormat**)valueTok.pointer;
+ delete value[kFull];
+ delete value[kAbbreviate];
+ //delete[] value;
+ uprv_free(value);
+ }
+ }
+ delete htable;
+}
+
+
+void
+TimeUnitFormat::copyHash(const Hashtable* source, Hashtable* target, UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return;
+ }
+ int32_t pos = -1;
+ const UHashElement* element = NULL;
+ if ( source ) {
+ while ( (element = source->nextElement(pos)) != NULL ) {
+ const UHashTok keyTok = element->key;
+ const UnicodeString* key = (UnicodeString*)keyTok.pointer;
+ const UHashTok valueTok = element->value;
+ const MessageFormat** value = (const MessageFormat**)valueTok.pointer;
+ //MessageFormat** newVal = new MessageFormat*[kTotal];
+ MessageFormat** newVal = (MessageFormat**)uprv_malloc(2*sizeof(MessageFormat*));
+ newVal[0] = (MessageFormat*)value[0]->clone();
+ newVal[1] = (MessageFormat*)value[1]->clone();
+ target->put(UnicodeString(*key), newVal, status);
+ if ( U_FAILURE(status) ) {
+ delete newVal[0];
+ delete newVal[1];
+ delete [] newVal;
+ return;
+ }
+ }
+ }
+}
+
+
+U_CDECL_BEGIN
+
+/**
+ * set hash table value comparator
+ *
+ * @param val1 one value in comparison
+ * @param val2 the other value in comparison
+ * @return TRUE if 2 values are the same, FALSE otherwise
+ */
+static UBool U_CALLCONV hashTableValueComparator(UHashTok val1, UHashTok val2);
+
+U_CDECL_END
+
+UBool
+U_CALLCONV hashTableValueComparator(UHashTok val1, UHashTok val2) {
+ const MessageFormat** pattern1 = (const MessageFormat**)val1.pointer;
+ const MessageFormat** pattern2 = (const MessageFormat**)val2.pointer;
+ return *pattern1[0] == *pattern2[0] && *pattern1[1] == *pattern2[1];
+}
+
+
+Hashtable*
+TimeUnitFormat::initHash(UErrorCode& status) {
+ if ( U_FAILURE(status) ) {
+ return NULL;
+ }
+ Hashtable* hTable;
+ if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ hTable->setValueCompartor(hashTableValueComparator);
+ return hTable;
+}
+
+
+const char*
+TimeUnitFormat::getTimeUnitName(TimeUnit::UTimeUnitFields unitField,
+ UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ switch (unitField) {
+ case TimeUnit::UTIMEUNIT_YEAR:
+ return gTimeUnitYear;
+ case TimeUnit::UTIMEUNIT_MONTH:
+ return gTimeUnitMonth;
+ case TimeUnit::UTIMEUNIT_DAY:
+ return gTimeUnitDay;
+ case TimeUnit::UTIMEUNIT_WEEK:
+ return gTimeUnitWeek;
+ case TimeUnit::UTIMEUNIT_HOUR:
+ return gTimeUnitHour;
+ case TimeUnit::UTIMEUNIT_MINUTE:
+ return gTimeUnitMinute;
+ case TimeUnit::UTIMEUNIT_SECOND:
+ return gTimeUnitSecond;
+ default:
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+}
+
+U_NAMESPACE_END
+
+#endif
Modified: trunk/source/i18n/unicode/currpinf.h
===================================================================
--- trunk/source/i18n/unicode/currpinf.h 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/i18n/unicode/currpinf.h 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,259 +1,259 @@
-/*
- *******************************************************************************
- * Copyright (C) 2009, International Business Machines Corporation and *
- * others. All Rights Reserved. *
- *******************************************************************************
- */
-#ifndef CURRPINF_H
-#define CURRPINF_H
-
-#include "unicode/utypes.h"
-
-/**
- * \file
- * \brief C++ API: Currency Plural Information used by Decimal Format
- */
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/unistr.h"
-
-union UHashTok;
-
-U_NAMESPACE_BEGIN
-
-class Locale;
-class PluralRules;
-class Hashtable;
-
-/**
- * This class represents the information needed by
- * DecimalFormat to format currency plural,
- * such as "3.00 US dollars" or "1.00 US dollar".
- * DecimalFormat creates for itself an instance of
- * CurrencyPluralInfo from its locale data.
- * If you need to change any of these symbols, you can get the
- * CurrencyPluralInfo object from your
- * DecimalFormat and modify it.
- *
- * Following are the information needed for currency plural format and parse:
- * locale information,
- * plural rule of the locale,
- * currency plural pattern of the locale.
- *
- * @draft ICU 4.2
- */
-class U_I18N_API CurrencyPluralInfo : public UObject {
-public:
-
- /**
- * Create a CurrencyPluralInfo object for the default locale.
- * @param status output param set to success/failure code on exit
- * @draft ICU 4.2
- */
- CurrencyPluralInfo(UErrorCode& status);
-
- /**
- * Create a CurrencyPluralInfo object for the given locale.
- * @param locale the locale
- * @param status output param set to success/failure code on exit
- * @draft ICU 4.2
- */
- CurrencyPluralInfo(const Locale& locale, UErrorCode& status);
-
- /**
- * Copy constructor
- *
- * @draft ICU 4.2
- */
- CurrencyPluralInfo(const CurrencyPluralInfo& info);
-
-
- /**
- * Assignment operator
- *
- * @draft ICU 4.2
- */
- CurrencyPluralInfo& operator=(const CurrencyPluralInfo& info);
-
-
- /**
- * Destructor
- *
- * @draft ICU 4.2
- */
- virtual ~CurrencyPluralInfo();
-
-
- /**
- * Equal operator.
- *
- * @draft ICU 4.2
- */
- UBool operator==(const CurrencyPluralInfo& info) const;
-
-
- /**
- * Not equal operator
- *
- * @draft ICU 4.2
- */
- UBool operator!=(const CurrencyPluralInfo& info) const;
-
-
- /**
- * Clone
- *
- * @draft ICU 4.2
- */
- CurrencyPluralInfo* clone() const;
-
-
- /**
- * Gets plural rules of this locale, used for currency plural format
- *
- * @return plural rule
- * @draft ICU 4.2
- */
- const PluralRules* getPluralRules() const;
-
- /**
- * Given a plural count, gets currency plural pattern of this locale,
- * used for currency plural format
- *
- * @param pluralCount currency plural count
- * @param result output param to receive the pattern
- * @return a currency plural pattern based on plural count
- * @draft ICU 4.2
- */
- UnicodeString& getCurrencyPluralPattern(const UnicodeString& pluralCount,
- UnicodeString& result) const;
-
- /**
- * Get locale
- *
- * @return locale
- * @draft ICU 4.2
- */
- const Locale& getLocale() const;
-
- /**
- * Set plural rules.
- * The plural rule is set when CurrencyPluralInfo
- * instance is created.
- * You can call this method to reset plural rules only if you want
- * to modify the default plural rule of the locale.
- *
- * @param ruleDescription new plural rule description
- * @param status output param set to success/failure code on exit
- * @draft ICU 4.2
- */
- void setPluralRules(const UnicodeString& ruleDescription,
- UErrorCode& status);
-
- /**
- * Set currency plural pattern.
- * The currency plural pattern is set when CurrencyPluralInfo
- * instance is created.
- * You can call this method to reset currency plural pattern only if
- * you want to modify the default currency plural pattern of the locale.
- *
- * @param pluralCount the plural count for which the currency pattern will
- * be overridden.
- * @param pattern the new currency plural pattern
- * @param status output param set to success/failure code on exit
- * @draft ICU 4.2
- */
- void setCurrencyPluralPattern(const UnicodeString& pluralCount,
- const UnicodeString& pattern,
- UErrorCode& status);
-
- /**
- * Set locale
- *
- * @param loc the new locale to set
- * @param status output param set to success/failure code on exit
- * @draft ICU 4.2
- */
- void setLocale(const Locale& loc, UErrorCode& status);
-
- /**
- * ICU "poor man's RTTI", returns a UClassID for the actual class.
- *
- * @draft ICU 4.2
- */
- virtual UClassID getDynamicClassID() const;
-
- /**
- * ICU "poor man's RTTI", returns a UClassID for this class.
- *
- * @draft ICU 4.2
- */
- static UClassID U_EXPORT2 getStaticClassID();
-
-private:
- friend class DecimalFormat;
-
- void initialize(const Locale& loc, UErrorCode& status);
-
- void setupCurrencyPluralPattern(const Locale& loc, UErrorCode& status);
-
- /*
- * delete hash table
- *
- * @param hTable hash table to be deleted
- */
- void deleteHash(Hashtable* hTable);
-
-
- /*
- * initialize hash table
- *
- * @param status output param set to success/failure code on exit
- * @return hash table initialized
- */
- Hashtable* initHash(UErrorCode& status);
-
-
-
- /**
- * copy hash table
- *
- * @param source the source to copy from
- * @param target the target to copy to
- */
- void copyHash(const Hashtable* source, Hashtable* target, UErrorCode& status);
-
- //-------------------- private data member ---------------------
- // map from plural count to currency plural pattern, for example
- // a plural pattern defined in "CurrencyUnitPatterns" is
- // "one{{0} {1}}", in which "one" is a plural count
- // and "{0} {1}" is a currency plural pattern".
- // The currency plural pattern saved in this mapping is the pattern
- // defined in "CurrencyUnitPattern" by replacing
- // {0} with the number format pattern,
- // and {1} with 3 currency sign.
- Hashtable* fPluralCountToCurrencyUnitPattern;
-
- /*
- * The plural rule is used to format currency plural name,
- * for example: "3.00 US Dollars".
- * If there are 3 currency signs in the currency patttern,
- * the 3 currency signs will be replaced by currency plural name.
- */
- PluralRules* fPluralRules;
-
- // locale
- Locale* fLocale;
-};
-
-
-inline UBool
-CurrencyPluralInfo::operator!=(const CurrencyPluralInfo& info) const { return !operator==(info); }
-
-U_NAMESPACE_END
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
-
-#endif // _CURRPINFO
-//eof
+/*
+ *******************************************************************************
+ * Copyright (C) 2009, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+#ifndef CURRPINF_H
+#define CURRPINF_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Currency Plural Information used by Decimal Format
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+
+union UHashTok;
+
+U_NAMESPACE_BEGIN
+
+class Locale;
+class PluralRules;
+class Hashtable;
+
+/**
+ * This class represents the information needed by
+ * DecimalFormat to format currency plural,
+ * such as "3.00 US dollars" or "1.00 US dollar".
+ * DecimalFormat creates for itself an instance of
+ * CurrencyPluralInfo from its locale data.
+ * If you need to change any of these symbols, you can get the
+ * CurrencyPluralInfo object from your
+ * DecimalFormat and modify it.
+ *
+ * Following are the information needed for currency plural format and parse:
+ * locale information,
+ * plural rule of the locale,
+ * currency plural pattern of the locale.
+ *
+ * @draft ICU 4.2
+ */
+class U_I18N_API CurrencyPluralInfo : public UObject {
+public:
+
+ /**
+ * Create a CurrencyPluralInfo object for the default locale.
+ * @param status output param set to success/failure code on exit
+ * @draft ICU 4.2
+ */
+ CurrencyPluralInfo(UErrorCode& status);
+
+ /**
+ * Create a CurrencyPluralInfo object for the given locale.
+ * @param locale the locale
+ * @param status output param set to success/failure code on exit
+ * @draft ICU 4.2
+ */
+ CurrencyPluralInfo(const Locale& locale, UErrorCode& status);
+
+ /**
+ * Copy constructor
+ *
+ * @draft ICU 4.2
+ */
+ CurrencyPluralInfo(const CurrencyPluralInfo& info);
+
+
+ /**
+ * Assignment operator
+ *
+ * @draft ICU 4.2
+ */
+ CurrencyPluralInfo& operator=(const CurrencyPluralInfo& info);
+
+
+ /**
+ * Destructor
+ *
+ * @draft ICU 4.2
+ */
+ virtual ~CurrencyPluralInfo();
+
+
+ /**
+ * Equal operator.
+ *
+ * @draft ICU 4.2
+ */
+ UBool operator==(const CurrencyPluralInfo& info) const;
+
+
+ /**
+ * Not equal operator
+ *
+ * @draft ICU 4.2
+ */
+ UBool operator!=(const CurrencyPluralInfo& info) const;
+
+
+ /**
+ * Clone
+ *
+ * @draft ICU 4.2
+ */
+ CurrencyPluralInfo* clone() const;
+
+
+ /**
+ * Gets plural rules of this locale, used for currency plural format
+ *
+ * @return plural rule
+ * @draft ICU 4.2
+ */
+ const PluralRules* getPluralRules() const;
+
+ /**
+ * Given a plural count, gets currency plural pattern of this locale,
+ * used for currency plural format
+ *
+ * @param pluralCount currency plural count
+ * @param result output param to receive the pattern
+ * @return a currency plural pattern based on plural count
+ * @draft ICU 4.2
+ */
+ UnicodeString& getCurrencyPluralPattern(const UnicodeString& pluralCount,
+ UnicodeString& result) const;
+
+ /**
+ * Get locale
+ *
+ * @return locale
+ * @draft ICU 4.2
+ */
+ const Locale& getLocale() const;
+
+ /**
+ * Set plural rules.
+ * The plural rule is set when CurrencyPluralInfo
+ * instance is created.
+ * You can call this method to reset plural rules only if you want
+ * to modify the default plural rule of the locale.
+ *
+ * @param ruleDescription new plural rule description
+ * @param status output param set to success/failure code on exit
+ * @draft ICU 4.2
+ */
+ void setPluralRules(const UnicodeString& ruleDescription,
+ UErrorCode& status);
+
+ /**
+ * Set currency plural pattern.
+ * The currency plural pattern is set when CurrencyPluralInfo
+ * instance is created.
+ * You can call this method to reset currency plural pattern only if
+ * you want to modify the default currency plural pattern of the locale.
+ *
+ * @param pluralCount the plural count for which the currency pattern will
+ * be overridden.
+ * @param pattern the new currency plural pattern
+ * @param status output param set to success/failure code on exit
+ * @draft ICU 4.2
+ */
+ void setCurrencyPluralPattern(const UnicodeString& pluralCount,
+ const UnicodeString& pattern,
+ UErrorCode& status);
+
+ /**
+ * Set locale
+ *
+ * @param loc the new locale to set
+ * @param status output param set to success/failure code on exit
+ * @draft ICU 4.2
+ */
+ void setLocale(const Locale& loc, UErrorCode& status);
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @draft ICU 4.2
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @draft ICU 4.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+private:
+ friend class DecimalFormat;
+
+ void initialize(const Locale& loc, UErrorCode& status);
+
+ void setupCurrencyPluralPattern(const Locale& loc, UErrorCode& status);
+
+ /*
+ * delete hash table
+ *
+ * @param hTable hash table to be deleted
+ */
+ void deleteHash(Hashtable* hTable);
+
+
+ /*
+ * initialize hash table
+ *
+ * @param status output param set to success/failure code on exit
+ * @return hash table initialized
+ */
+ Hashtable* initHash(UErrorCode& status);
+
+
+
+ /**
+ * copy hash table
+ *
+ * @param source the source to copy from
+ * @param target the target to copy to
+ */
+ void copyHash(const Hashtable* source, Hashtable* target, UErrorCode& status);
+
+ //-------------------- private data member ---------------------
+ // map from plural count to currency plural pattern, for example
+ // a plural pattern defined in "CurrencyUnitPatterns" is
+ // "one{{0} {1}}", in which "one" is a plural count
+ // and "{0} {1}" is a currency plural pattern".
+ // The currency plural pattern saved in this mapping is the pattern
+ // defined in "CurrencyUnitPattern" by replacing
+ // {0} with the number format pattern,
+ // and {1} with 3 currency sign.
+ Hashtable* fPluralCountToCurrencyUnitPattern;
+
+ /*
+ * The plural rule is used to format currency plural name,
+ * for example: "3.00 US Dollars".
+ * If there are 3 currency signs in the currency patttern,
+ * the 3 currency signs will be replaced by currency plural name.
+ */
+ PluralRules* fPluralRules;
+
+ // locale
+ Locale* fLocale;
+};
+
+
+inline UBool
+CurrencyPluralInfo::operator!=(const CurrencyPluralInfo& info) const { return !operator==(info); }
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _CURRPINFO
+//eof
Modified: trunk/source/i18n/unicode/dtitvfmt.h
===================================================================
--- trunk/source/i18n/unicode/dtitvfmt.h 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/i18n/unicode/dtitvfmt.h 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,972 +1,972 @@
-/********************************************************************************
-* Copyright (C) 2008-2009, International Business Machines Corporation and others. All Rights Reserved.
-*******************************************************************************
-*
-* File DTITVFMT.H
-*
-*******************************************************************************
-*/
-
-#ifndef __DTITVFMT_H__
-#define __DTITVFMT_H__
-
-
-#include "unicode/utypes.h"
-
-/**
- * \file
- * \brief C++ API: Format and parse date interval in a language-independent manner.
- */
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/ucal.h"
-#include "unicode/smpdtfmt.h"
-#include "unicode/dtintrv.h"
-#include "unicode/dtitvinf.h"
-#include "unicode/dtptngen.h"
-
-U_NAMESPACE_BEGIN
-
-
-
-/**
- * DateIntervalFormat is a class for formatting and parsing date
- * intervals in a language-independent manner.
- * Date interval formatting is supported in Gregorian calendar only.
- * And only formatting is supported. Parsing is not supported.
- *
- * <P>
- * Date interval means from one date to another date,
- * for example, from "Jan 11, 2008" to "Jan 18, 2008".
- * We introduced class DateInterval to represent it.
- * DateInterval is a pair of UDate, which is
- * the standard milliseconds since 24:00 GMT, Jan 1, 1970.
- *
- * <P>
- * DateIntervalFormat formats a DateInterval into
- * text as compactly as possible.
- * For example, the date interval format from "Jan 11, 2008" to "Jan 18,. 2008"
- * is "Jan 11-18, 2008" for English.
- * And it parses text into DateInterval,
- * although initially, parsing is not supported.
- *
- * <P>
- * There is no structural information in date time patterns.
- * For any punctuations and string literals inside a date time pattern,
- * we do not know whether it is just a separator, or a prefix, or a suffix.
- * Without such information, so, it is difficult to generate a sub-pattern
- * (or super-pattern) by algorithm.
- * So, formatting a DateInterval is pattern-driven. It is very
- * similar to formatting in SimpleDateFormat.
- * We introduce class DateIntervalInfo to save date interval
- * patterns, similar to date time pattern in SimpleDateFormat.
- *
- * <P>
- * Logically, the interval patterns are mappings
- * from (skeleton, the_largest_different_calendar_field)
- * to (date_interval_pattern).
- *
- * <P>
- * A skeleton
- * <ol>
- * <li>
- * only keeps the field pattern letter and ignores all other parts
- * in a pattern, such as space, punctuations, and string literals.
- * </li>
- * <li>
- * hides the order of fields.
- * </li>
- * <li>
- * might hide a field's pattern letter length.
- * </li>
- * </ol>
- *
- * For those non-digit calendar fields, the pattern letter length is
- * important, such as MMM, MMMM, and MMMMM; EEE and EEEE,
- * and the field's pattern letter length is honored.
- *
- * For the digit calendar fields, such as M or MM, d or dd, yy or yyyy,
- * the field pattern length is ignored and the best match, which is defined
- * in date time patterns, will be returned without honor the field pattern
- * letter length in skeleton.
- *
- * <P>
- * The calendar fields we support for interval formatting are:
- * year, month, date, day-of-week, am-pm, hour, hour-of-day, and minute.
- * Those calendar fields can be defined in the following order:
- * year > month > date > hour (in day) > minute
- *
- * The largest different calendar fields between 2 calendars is the
- * first different calendar field in above order.
- *
- * For example: the largest different calendar fields between "Jan 10, 2007"
- * and "Feb 20, 2008" is year.
- *
- * <P>
- * For other calendar fields, the compact interval formatting is not
- * supported. And the interval format will be fall back to fall-back
- * patterns, which is mostly "{date0} - {date1}".
- *
- * <P>
- * There is a set of pre-defined static skeleton strings.
- * There are pre-defined interval patterns for those pre-defined skeletons
- * in locales' resource files.
- * For example, for a skeleton UDAT_YEAR_ABBR_MONTH_DAY, which is "yMMMd",
- * in en_US, if the largest different calendar field between date1 and date2
- * is "year", the date interval pattern is "MMM d, yyyy - MMM d, yyyy",
- * such as "Jan 10, 2007 - Jan 10, 2008".
- * If the largest different calendar field between date1 and date2 is "month",
- * the date interval pattern is "MMM d - MMM d, yyyy",
- * such as "Jan 10 - Feb 10, 2007".
- * If the largest different calendar field between date1 and date2 is "day",
- * the date interval pattern is ""MMM d-d, yyyy", such as "Jan 10-20, 2007".
- *
- * For date skeleton, the interval patterns when year, or month, or date is
- * different are defined in resource files.
- * For time skeleton, the interval patterns when am/pm, or hour, or minute is
- * different are defined in resource files.
- *
- * <P>
- * If a skeleton is not found in a locale's DateIntervalInfo, which means
- * the interval patterns for the skeleton is not defined in resource file,
- * the interval pattern will falls back to the interval "fallback" pattern
- * defined in resource file.
- * If the interval "fallback" pattern is not defined, the default fall-back
- * is "{date0} - {data1}".
- *
- * <P>
- * For the combination of date and time,
- * The rule to generate interval patterns are:
- * <ol>
- * <li>
- * when the year, month, or day differs, falls back to fall-back
- * interval pattern, which mostly is the concatenate the two original
- * expressions with a separator between,
- * For example, interval pattern from "Jan 10, 2007 10:10 am"
- * to "Jan 11, 2007 10:10am" is
- * "Jan 10, 2007 10:10 am - Jan 11, 2007 10:10am"
- * </li>
- * <li>
- * otherwise, present the date followed by the range expression
- * for the time.
- * For example, interval pattern from "Jan 10, 2007 10:10 am"
- * to "Jan 10, 2007 11:10am" is "Jan 10, 2007 10:10 am - 11:10am"
- * </li>
- * </ol>
- *
- *
- * <P>
- * If two dates are the same, the interval pattern is the single date pattern.
- * For example, interval pattern from "Jan 10, 2007" to "Jan 10, 2007" is
- * "Jan 10, 2007".
- *
- * Or if the presenting fields between 2 dates have the exact same values,
- * the interval pattern is the single date pattern.
- * For example, if user only requests year and month,
- * the interval pattern from "Jan 10, 2007" to "Jan 20, 2007" is "Jan 2007".
- *
- * <P>
- * DateIntervalFormat needs the following information for correct
- * formatting: time zone, calendar type, pattern, date format symbols,
- * and date interval patterns.
- * It can be instantiated in 2 ways:
- * <ol>
- * <li>
- * create an instance using default or given locale plus given skeleton.
- * Users are encouraged to created date interval formatter this way and
- * to use the pre-defined skeleton macros, such as
- * UDAT_YEAR_NUM_MONTH, which consists the calendar fields and
- * the format style.
- * </li>
- * <li>
- * create an instance using default or given locale plus given skeleton
- * plus a given DateIntervalInfo.
- * This factory method is for powerful users who want to provide their own
- * interval patterns.
- * Locale provides the timezone, calendar, and format symbols information.
- * Local plus skeleton provides full pattern information.
- * DateIntervalInfo provides the date interval patterns.
- * </li>
- * </ol>
- *
- * <P>
- * For the calendar field pattern letter, such as G, y, M, d, a, h, H, m, s etc.
- * DateIntervalFormat uses the same syntax as that of
- * DateTime format.
- *
- * <P>
- * Code Sample: general usage
- * <pre>
- * \code
- * // the date interval object which the DateIntervalFormat formats on
- * // and parses into
- * DateInterval* dtInterval = new DateInterval(1000*3600*24, 1000*3600*24*2);
- * UErrorCode status = U_ZERO_ERROR;
- * DateIntervalFormat* dtIntervalFmt = DateIntervalFormat::createInstance(
- * UDAT_YEAR_MONTH_DAY,
- * Locale("en", "GB", ""), status);
- * UnicodeUnicodeString dateIntervalString;
- * FieldPosition pos = 0;
- * // formatting
- * dtIntervalFmt->format(dtInterval, dateIntervalUnicodeString, pos, status);
- * delete dtIntervalFmt;
- * \endcode
- * </pre>
- */
-
-class U_I18N_API DateIntervalFormat : public Format {
-public:
-
- /**
- * Construct a DateIntervalFormat from skeleton and the default locale.
- *
- * This is a convenient override of
- * createInstance(const UnicodeString& skeleton, const Locale& locale,
- * UErrorCode&)
- * with the value of locale as default locale.
- *
- * @param skeleton the skeleton on which interval format based.
- * @param status output param set to success/failure code on exit
- * @return a date time interval formatter which the caller owns.
- * @stable ICU 4.0
- */
- static DateIntervalFormat* U_EXPORT2 createInstance(
- const UnicodeString& skeleton,
- UErrorCode& status);
-
- /**
- * Construct a DateIntervalFormat from skeleton and a given locale.
- * <P>
- * In this factory method,
- * the date interval pattern information is load from resource files.
- * Users are encouraged to created date interval formatter this way and
- * to use the pre-defined skeleton macros.
- *
- * <P>
- * There are pre-defined skeletons (defined in udate.h) having predefined
- * interval patterns in resource files.
- * Users are encouraged to use those macros.
- * For example:
- * DateIntervalFormat::createInstance(UDAT_MONTH_DAY, status)
- *
- * The given Locale provides the interval patterns.
- * For example, for en_GB, if skeleton is UDAT_YEAR_ABBR_MONTH_WEEKDAY_DAY,
- * which is "yMMMEEEd",
- * the interval patterns defined in resource file to above skeleton are:
- * "EEE, d MMM, yyyy - EEE, d MMM, yyyy" for year differs,
- * "EEE, d MMM - EEE, d MMM, yyyy" for month differs,
- * "EEE, d - EEE, d MMM, yyyy" for day differs,
- * @param skeleton the skeleton on which interval format based.
- * @param locale the given locale
- * @param status output param set to success/failure code on exit
- * @return a date time interval formatter which the caller owns.
- * @stable ICU 4.0
- */
-
- static DateIntervalFormat* U_EXPORT2 createInstance(
- const UnicodeString& skeleton,
- const Locale& locale,
- UErrorCode& status);
-
- /**
- * Construct a DateIntervalFormat from skeleton
- * DateIntervalInfo, and default locale.
- *
- * This is a convenient override of
- * createInstance(const UnicodeString& skeleton, const Locale& locale,
- * const DateIntervalInfo& dtitvinf, UErrorCode&)
- * with the locale value as default locale.
- *
- * @param skeleton the skeleton on which interval format based.
- * @param dtitvinf the DateIntervalInfo object.
- * @param status output param set to success/failure code on exit
- * @return a date time interval formatter which the caller owns.
- * @stable ICU 4.0
- */
- static DateIntervalFormat* U_EXPORT2 createInstance(
- const UnicodeString& skeleton,
- const DateIntervalInfo& dtitvinf,
- UErrorCode& status);
-
- /**
- * Construct a DateIntervalFormat from skeleton
- * a DateIntervalInfo, and the given locale.
- *
- * <P>
- * In this factory method, user provides its own date interval pattern
- * information, instead of using those pre-defined data in resource file.
- * This factory method is for powerful users who want to provide their own
- * interval patterns.
- * <P>
- * There are pre-defined skeletons (defined in udate.h) having predefined
- * interval patterns in resource files.
- * Users are encouraged to use those macros.
- * For example:
- * DateIntervalFormat::createInstance(UDAT_MONTH_DAY, status)
- *
- * The DateIntervalInfo provides the interval patterns.
- * and the DateIntervalInfo ownership remains to the caller.
- *
- * User are encouraged to set default interval pattern in DateIntervalInfo
- * as well, if they want to set other interval patterns ( instead of
- * reading the interval patterns from resource files).
- * When the corresponding interval pattern for a largest calendar different
- * field is not found ( if user not set it ), interval format fallback to
- * the default interval pattern.
- * If user does not provide default interval pattern, it fallback to
- * "{date0} - {date1}"
- *
- * @param skeleton the skeleton on which interval format based.
- * @param locale the given locale
- * @param dtitvinf the DateIntervalInfo object.
- * @param status output param set to success/failure code on exit
- * @return a date time interval formatter which the caller owns.
- * @stable ICU 4.0
- */
- static DateIntervalFormat* U_EXPORT2 createInstance(
- const UnicodeString& skeleton,
- const Locale& locale,
- const DateIntervalInfo& dtitvinf,
- UErrorCode& status);
-
- /**
- * Destructor.
- * @stable ICU 4.0
- */
- virtual ~DateIntervalFormat();
-
- /**
- * Clone this Format object polymorphically. The caller owns the result and
- * should delete it when done.
- * @return A copy of the object.
- * @stable ICU 4.0
- */
- virtual Format* clone(void) const;
-
- /**
- * Return true if the given Format objects are semantically equal. Objects
- * of different subclasses are considered unequal.
- * @param other the object to be compared with.
- * @return true if the given Format objects are semantically equal.
- * @stable ICU 4.0
- */
- virtual UBool operator==(const Format& other) const;
-
- /**
- * Return true if the given Format objects are not semantically equal.
- * Objects of different subclasses are considered unequal.
- * @param other the object to be compared with.
- * @return true if the given Format objects are not semantically equal.
- * @stable ICU 4.0
- */
- UBool operator!=(const Format& other) const;
-
- /**
- * Format an object to produce a string. This method handles Formattable
- * objects with a DateInterval type.
- * If a the Formattable object type is not a DateInterval,
- * then it returns a failing UErrorCode.
- *
- * @param obj The object to format.
- * Must be a DateInterval.
- * @param appendTo Output parameter to receive result.
- * Result is appended to existing contents.
- * @param fieldPosition On input: an alignment field, if desired.
- * On output: the offsets of the alignment field.
- * @param status Output param filled with success/failure status.
- * @return Reference to 'appendTo' parameter.
- * @stable ICU 4.0
- */
- virtual UnicodeString& format(const Formattable& obj,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition,
- UErrorCode& status) const ;
-
-
-
- /**
- * Format a DateInterval to produce a string.
- *
- * @param dtInterval DateInterval to be formatted.
- * @param appendTo Output parameter to receive result.
- * Result is appended to existing contents.
- * @param fieldPosition On input: an alignment field, if desired.
- * On output: the offsets of the alignment field.
- * @param status Output param filled with success/failure status.
- * @return Reference to 'appendTo' parameter.
- * @stable ICU 4.0
- */
- UnicodeString& format(const DateInterval* dtInterval,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition,
- UErrorCode& status) const ;
-
-
- /**
- * Format 2 Calendars to produce a string.
- *
- * Note: "fromCalendar" and "toCalendar" are not const,
- * since calendar is not const in SimpleDateFormat::format(Calendar&),
- *
- * @param fromCalendar calendar set to the from date in date interval
- * to be formatted into date interval string
- * @param toCalendar calendar set to the to date in date interval
- * to be formatted into date interval string
- * @param appendTo Output parameter to receive result.
- * Result is appended to existing contents.
- * @param fieldPosition On input: an alignment field, if desired.
- * On output: the offsets of the alignment field.
- * @param status Output param filled with success/failure status.
- * Caller needs to make sure it is SUCCESS
- * at the function entrance
- * @return Reference to 'appendTo' parameter.
- * @stable ICU 4.0
- */
- UnicodeString& format(Calendar& fromCalendar,
- Calendar& toCalendar,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition,
- UErrorCode& status) const ;
-
- /**
- * Date interval parsing is not supported. Please do not use.
- * <P>
- * This method should handle parsing of
- * date time interval strings into Formattable objects with
- * DateInterval type, which is a pair of UDate.
- * <P>
- * Before calling, set parse_pos.index to the offset you want to start
- * parsing at in the source. After calling, parse_pos.index is the end of
- * the text you parsed. If error occurs, index is unchanged.
- * <P>
- * When parsing, leading whitespace is discarded (with a successful parse),
- * while trailing whitespace is left as is.
- * <P>
- * See Format::parseObject() for more.
- *
- * @param source The string to be parsed into an object.
- * @param result Formattable to be set to the parse result.
- * If parse fails, return contents are undefined.
- * @param parse_pos The position to start parsing at. Since no parsing
- * is supported, upon return this param is unchanged.
- * @return A newly created Formattable* object, or NULL
- * on failure. The caller owns this and should
- * delete it when done.
- * @internal ICU 4.0
- */
- virtual void parseObject(const UnicodeString& source,
- Formattable& result,
- ParsePosition& parse_pos) const;
-
-
- /**
- * Gets the date time interval patterns.
- * @return the date time interval patterns associated with
- * this date interval formatter.
- * @stable ICU 4.0
- */
- const DateIntervalInfo* getDateIntervalInfo(void) const;
-
-
- /**
- * Set the date time interval patterns.
- * @param newIntervalPatterns the given interval patterns to copy.
- * @param status output param set to success/failure code on exit
- * @stable ICU 4.0
- */
- void setDateIntervalInfo(const DateIntervalInfo& newIntervalPatterns,
- UErrorCode& status);
-
-
- /**
- * Gets the date formatter
- * @return the date formatter associated with this date interval formatter.
- * @stable ICU 4.0
- */
- const DateFormat* getDateFormat(void) const;
-
- /**
- * Return the class ID for this class. This is useful only for comparing to
- * a return value from getDynamicClassID(). For example:
- * <pre>
- * . Base* polymorphic_pointer = createPolymorphicObject();
- * . if (polymorphic_pointer->getDynamicClassID() ==
- * . erived::getStaticClassID()) ...
- * </pre>
- * @return The class ID for all objects of this class.
- * @stable ICU 4.0
- */
- static UClassID U_EXPORT2 getStaticClassID(void);
-
- /**
- * 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 4.0
- */
- virtual UClassID getDynamicClassID(void) const;
-
-protected:
-
- /**
- * Copy constructor.
- * @stable ICU 4.0
- */
- DateIntervalFormat(const DateIntervalFormat&);
-
- /**
- * Assignment operator.
- * @stable ICU 4.0
- */
- DateIntervalFormat& operator=(const DateIntervalFormat&);
-
-private:
-
- /*
- * This is for ICU internal use only. Please do not use.
- * Save the interval pattern information.
- * Interval pattern consists of 2 single date patterns and the separator.
- * For example, interval pattern "MMM d - MMM d, yyyy" consists
- * a single date pattern "MMM d", another single date pattern "MMM d, yyyy",
- * and a separator "-".
- * The pattern is divided into 2 parts. For above example,
- * the first part is "MMM d - ", and the second part is "MMM d, yyyy".
- * Also, the first date appears in an interval pattern could be
- * the earlier date or the later date.
- * And such information is saved in the interval pattern as well.
- * @internal ICU 4.0
- */
- struct PatternInfo {
- UnicodeString firstPart;
- UnicodeString secondPart;
- /**
- * Whether the first date in interval pattern is later date or not.
- * Fallback format set the default ordering.
- * And for a particular interval pattern, the order can be
- * overriden by prefixing the interval pattern with "latestFirst:" or
- * "earliestFirst:"
- * For example, given 2 date, Jan 10, 2007 to Feb 10, 2007.
- * if the fallback format is "{0} - {1}",
- * and the pattern is "d MMM - d MMM yyyy", the interval format is
- * "10 Jan - 10 Feb, 2007".
- * If the pattern is "latestFirst:d MMM - d MMM yyyy",
- * the interval format is "10 Feb - 10 Jan, 2007"
- */
- UBool laterDateFirst;
- };
-
-
- /**
- * default constructor
- * @internal ICU 4.0
- */
- DateIntervalFormat();
-
- /**
- * Construct a DateIntervalFormat from DateFormat,
- * a DateIntervalInfo, and skeleton.
- * DateFormat provides the timezone, calendar,
- * full pattern, and date format symbols information.
- * It should be a SimpleDateFormat object which
- * has a pattern in it.
- * the DateIntervalInfo provides the interval patterns.
- *
- * Note: the DateIntervalFormat takes ownership of both
- * DateFormat and DateIntervalInfo objects.
- * Caller should not delete them.
- *
- * @param locale the locale of this date interval formatter.
- * @param dtitvinf the DateIntervalInfo object to be adopted.
- * @param skeleton the skeleton of the date formatter
- * @param status output param set to success/failure code on exit
- * @internal ICU 4.0
- */
- DateIntervalFormat(const Locale& locale, DateIntervalInfo* dtItvInfo,
- const UnicodeString* skeleton, UErrorCode& status);
-
-
- /**
- * Construct a DateIntervalFormat from DateFormat
- * and a DateIntervalInfo.
- *
- * It is a wrapper of the constructor.
- *
- * @param locale the locale of this date interval formatter.
- * @param dtitvinf the DateIntervalInfo object to be adopted.
- * @param skeleton the skeleton of this formatter.
- * @param status Output param set to success/failure code.
- * @return a date time interval formatter which the caller owns.
- * @internal ICU 4.0
- */
- static DateIntervalFormat* U_EXPORT2 create(const Locale& locale,
- DateIntervalInfo* dtitvinf,
- const UnicodeString* skeleton,
- UErrorCode& status);
-
- /**
- * Create a simple date/time formatter from skeleton, given locale,
- * and date time pattern generator.
- *
- * @param skeleton the skeleton on which date format based.
- * @param locale the given locale.
- * @param dtpng the date time pattern generator.
- * @param status Output param to be set to success/failure code.
- * If it is failure, the returned date formatter will
- * be NULL.
- * @return a simple date formatter which the caller owns.
- * @internal ICU 4.0
- */
- static SimpleDateFormat* U_EXPORT2 createSDFPatternInstance(
- const UnicodeString& skeleton,
- const Locale& locale,
- DateTimePatternGenerator* dtpng,
- UErrorCode& status);
-
-
- /**
- * Below are for generating interval patterns local to the formatter
- */
-
-
- /**
- * Format 2 Calendars using fall-back interval pattern
- *
- * The full pattern used in this fall-back format is the
- * full pattern of the date formatter.
- *
- * @param fromCalendar calendar set to the from date in date interval
- * to be formatted into date interval string
- * @param toCalendar calendar set to the to date in date interval
- * to be formatted into date interval string
- * @param appendTo Output parameter to receive result.
- * Result is appended to existing contents.
- * @param pos On input: an alignment field, if desired.
- * On output: the offsets of the alignment field.
- * @param status output param set to success/failure code on exit
- * @return Reference to 'appendTo' parameter.
- * @internal ICU 4.0
- */
- UnicodeString& fallbackFormat(Calendar& fromCalendar,
- Calendar& toCalendar,
- UnicodeString& appendTo,
- FieldPosition& pos,
- UErrorCode& status) const;
-
-
-
- /**
- * Initialize interval patterns locale to this formatter
- *
- * This code is a bit complicated since
- * 1. the interval patterns saved in resource bundle files are interval
- * patterns based on date or time only.
- * It does not have interval patterns based on both date and time.
- * Interval patterns on both date and time are algorithm generated.
- *
- * For example, it has interval patterns on skeleton "dMy" and "hm",
- * but it does not have interval patterns on skeleton "dMyhm".
- *
- * The rule to generate interval patterns for both date and time skeleton are
- * 1) when the year, month, or day differs, concatenate the two original
- * expressions with a separator between,
- * For example, interval pattern from "Jan 10, 2007 10:10 am"
- * to "Jan 11, 2007 10:10am" is
- * "Jan 10, 2007 10:10 am - Jan 11, 2007 10:10am"
- *
- * 2) otherwise, present the date followed by the range expression
- * for the time.
- * For example, interval pattern from "Jan 10, 2007 10:10 am"
- * to "Jan 10, 2007 11:10am" is
- * "Jan 10, 2007 10:10 am - 11:10am"
- *
- * 2. even a pattern does not request a certain calendar field,
- * the interval pattern needs to include such field if such fields are
- * different between 2 dates.
- * For example, a pattern/skeleton is "hm", but the interval pattern
- * includes year, month, and date when year, month, and date differs.
- *
- *
- * @param status output param set to success/failure code on exit
- * @internal ICU 4.0
- */
- void initializePattern(UErrorCode& status);
-
-
-
- /**
- * Set fall back interval pattern given a calendar field,
- * a skeleton, and a date time pattern generator.
- * @param field the largest different calendar field
- * @param skeleton a skeleton
- * @param status output param set to success/failure code on exit
- * @internal ICU 4.0
- */
- void setFallbackPattern(UCalendarDateFields field,
- const UnicodeString& skeleton,
- UErrorCode& status);
-
-
-
- /**
- * get separated date and time skeleton from a combined skeleton.
- *
- * The difference between date skeleton and normalizedDateSkeleton are:
- * 1. both 'y' and 'd' are appeared only once in normalizeDateSkeleton
- * 2. 'E' and 'EE' are normalized into 'EEE'
- * 3. 'MM' is normalized into 'M'
- *
- ** the difference between time skeleton and normalizedTimeSkeleton are:
- * 1. both 'H' and 'h' are normalized as 'h' in normalized time skeleton,
- * 2. 'a' is omitted in normalized time skeleton.
- * 3. there is only one appearance for 'h', 'm','v', 'z' in normalized time
- * skeleton
- *
- *
- * @param skeleton given combined skeleton.
- * @param date Output parameter for date only skeleton.
- * @param normalizedDate Output parameter for normalized date only
- *
- * @param time Output parameter for time only skeleton.
- * @param normalizedTime Output parameter for normalized time only
- * skeleton.
- *
- * @internal ICU 4.0
- */
- static void U_EXPORT2 getDateTimeSkeleton(const UnicodeString& skeleton,
- UnicodeString& date,
- UnicodeString& normalizedDate,
- UnicodeString& time,
- UnicodeString& normalizedTime);
-
-
-
- /**
- * Generate date or time interval pattern from resource,
- * and set them into the interval pattern locale to this formatter.
- *
- * It needs to handle the following:
- * 1. need to adjust field width.
- * For example, the interval patterns saved in DateIntervalInfo
- * includes "dMMMy", but not "dMMMMy".
- * Need to get interval patterns for dMMMMy from dMMMy.
- * Another example, the interval patterns saved in DateIntervalInfo
- * includes "hmv", but not "hmz".
- * Need to get interval patterns for "hmz' from 'hmv'
- *
- * 2. there might be no pattern for 'y' differ for skeleton "Md",
- * in order to get interval patterns for 'y' differ,
- * need to look for it from skeleton 'yMd'
- *
- * @param dateSkeleton normalized date skeleton
- * @param timeSkeleton normalized time skeleton
- * @return whether the resource is found for the skeleton.
- * TRUE if interval pattern found for the skeleton,
- * FALSE otherwise.
- * @internal ICU 4.0
- */
- UBool setSeparateDateTimePtn(const UnicodeString& dateSkeleton,
- const UnicodeString& timeSkeleton);
-
-
-
-
- /**
- * Generate interval pattern from existing resource
- *
- * It not only save the interval patterns,
- * but also return the extended skeleton and its best match skeleton.
- *
- * @param field largest different calendar field
- * @param skeleton skeleton
- * @param bestSkeleton the best match skeleton which has interval pattern
- * defined in resource
- * @param differenceInfo the difference between skeleton and best skeleton
- * 0 means the best matched skeleton is the same as input skeleton
- * 1 means the fields are the same, but field width are different
- * 2 means the only difference between fields are v/z,
- * -1 means there are other fields difference
- *
- * @param extendedSkeleton extended skeleton
- * @param extendedBestSkeleton extended best match skeleton
- * @return whether the interval pattern is found
- * through extending skeleton or not.
- * TRUE if interval pattern is found by
- * extending skeleton, FALSE otherwise.
- * @internal ICU 4.0
- */
- UBool setIntervalPattern(UCalendarDateFields field,
- const UnicodeString* skeleton,
- const UnicodeString* bestSkeleton,
- int8_t differenceInfo,
- UnicodeString* extendedSkeleton = NULL,
- UnicodeString* extendedBestSkeleton = NULL);
-
- /**
- * Adjust field width in best match interval pattern to match
- * the field width in input skeleton.
- *
- * TODO (xji) make a general solution
- * The adjusting rule can be:
- * 1. always adjust
- * 2. never adjust
- * 3. default adjust, which means adjust according to the following rules
- * 3.1 always adjust string, such as MMM and MMMM
- * 3.2 never adjust between string and numeric, such as MM and MMM
- * 3.3 always adjust year
- * 3.4 do not adjust 'd', 'h', or 'm' if h presents
- * 3.5 do not adjust 'M' if it is numeric(?)
- *
- * Since date interval format is well-formed format,
- * date and time skeletons are normalized previously,
- * till this stage, the adjust here is only "adjust strings, such as MMM
- * and MMMM, EEE and EEEE.
- *
- * @param inputSkeleton the input skeleton
- * @param bestMatchSkeleton the best match skeleton
- * @param bestMatchIntervalpattern the best match interval pattern
- * @param differenceInfo the difference between 2 skeletons
- * 1 means only field width differs
- * 2 means v/z exchange
- * @param adjustedIntervalPattern adjusted interval pattern
- * @internal ICU 4.0
- */
- static void U_EXPORT2 adjustFieldWidth(
- const UnicodeString& inputSkeleton,
- const UnicodeString& bestMatchSkeleton,
- const UnicodeString& bestMatchIntervalPattern,
- int8_t differenceInfo,
- UnicodeString& adjustedIntervalPattern);
-
- /**
- * Concat a single date pattern with a time interval pattern,
- * set it into the intervalPatterns, while field is time field.
- * This is used to handle time interval patterns on skeleton with
- * both time and date. Present the date followed by
- * the range expression for the time.
- * @param format date and time format
- * @param formatLen format string length
- * @param datePattern date pattern
- * @param field time calendar field: AM_PM, HOUR, MINUTE
- * @param status output param set to success/failure code on exit
- * @internal ICU 4.0
- */
- void concatSingleDate2TimeInterval(const UChar* format,
- int32_t formatLen,
- const UnicodeString& datePattern,
- UCalendarDateFields field,
- UErrorCode& status);
-
- /**
- * check whether a calendar field present in a skeleton.
- * @param field calendar field need to check
- * @param skeleton given skeleton on which to check the calendar field
- * @return true if field present in a skeleton.
- * @internal ICU 4.0
- */
- static UBool U_EXPORT2 fieldExistsInSkeleton(UCalendarDateFields field,
- const UnicodeString& skeleton);
-
-
- /**
- * Split interval patterns into 2 part.
- * @param intervalPattern interval pattern
- * @return the index in interval pattern which split the pattern into 2 part
- * @internal ICU 4.0
- */
- static int32_t U_EXPORT2 splitPatternInto2Part(const UnicodeString& intervalPattern);
-
-
- /**
- * Break interval patterns as 2 part and save them into pattern info.
- * @param field calendar field
- * @param intervalPattern interval pattern
- * @internal ICU 4.0
- */
- void setIntervalPattern(UCalendarDateFields field,
- const UnicodeString& intervalPattern);
-
-
- /**
- * Break interval patterns as 2 part and save them into pattern info.
- * @param field calendar field
- * @param intervalPattern interval pattern
- * @param laterDateFirst whether later date appear first in interval pattern
- * @internal ICU 4.0
- */
- void setIntervalPattern(UCalendarDateFields field,
- const UnicodeString& intervalPattern,
- UBool laterDateFirst);
-
-
- /**
- * Set pattern information.
- *
- * @param field calendar field
- * @param firstPart the first part in interval pattern
- * @param secondPart the second part in interval pattern
- * @param laterDateFirst whether the first date in intervalPattern
- * is earlier date or later date
- * @internal ICU 4.0
- */
- void setPatternInfo(UCalendarDateFields field,
- const UnicodeString* firstPart,
- const UnicodeString* secondpart,
- UBool laterDateFirst);
-
-
- // from calendar field to pattern letter
- static const UChar fgCalendarFieldToPatternLetter[];
-
-
- /**
- * The interval patterns for this locale.
- */
- DateIntervalInfo* fInfo;
-
- /**
- * The DateFormat object used to format single pattern
- */
- SimpleDateFormat* fDateFormat;
-
- /**
- * The 2 calendars with the from and to date.
- * could re-use the calendar in fDateFormat,
- * but keeping 2 calendars make it clear and clean.
- */
- Calendar* fFromCalendar;
- Calendar* fToCalendar;
-
- /**
- * Date time pattern generator
- */
- DateTimePatternGenerator* fDtpng;
-
- /**
- * Following are interval information relavent (locale) to this formatter.
- */
- UnicodeString fSkeleton;
- PatternInfo fIntervalPatterns[DateIntervalInfo::kIPI_MAX_INDEX];
-};
-
-
-
-
-
-
-inline UBool
-DateIntervalFormat::operator!=(const Format& other) const {
- return !operator==(other);
-}
-
-U_NAMESPACE_END
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
-
-#endif // _DTITVFMT_H__
-//eof
+/********************************************************************************
+* Copyright (C) 2008-2009, International Business Machines Corporation and others. All Rights Reserved.
+*******************************************************************************
+*
+* File DTITVFMT.H
+*
+*******************************************************************************
+*/
+
+#ifndef __DTITVFMT_H__
+#define __DTITVFMT_H__
+
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Format and parse date interval in a language-independent manner.
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/ucal.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/dtintrv.h"
+#include "unicode/dtitvinf.h"
+#include "unicode/dtptngen.h"
+
+U_NAMESPACE_BEGIN
+
+
+
+/**
+ * DateIntervalFormat is a class for formatting and parsing date
+ * intervals in a language-independent manner.
+ * Date interval formatting is supported in Gregorian calendar only.
+ * And only formatting is supported. Parsing is not supported.
+ *
+ * <P>
+ * Date interval means from one date to another date,
+ * for example, from "Jan 11, 2008" to "Jan 18, 2008".
+ * We introduced class DateInterval to represent it.
+ * DateInterval is a pair of UDate, which is
+ * the standard milliseconds since 24:00 GMT, Jan 1, 1970.
+ *
+ * <P>
+ * DateIntervalFormat formats a DateInterval into
+ * text as compactly as possible.
+ * For example, the date interval format from "Jan 11, 2008" to "Jan 18,. 2008"
+ * is "Jan 11-18, 2008" for English.
+ * And it parses text into DateInterval,
+ * although initially, parsing is not supported.
+ *
+ * <P>
+ * There is no structural information in date time patterns.
+ * For any punctuations and string literals inside a date time pattern,
+ * we do not know whether it is just a separator, or a prefix, or a suffix.
+ * Without such information, so, it is difficult to generate a sub-pattern
+ * (or super-pattern) by algorithm.
+ * So, formatting a DateInterval is pattern-driven. It is very
+ * similar to formatting in SimpleDateFormat.
+ * We introduce class DateIntervalInfo to save date interval
+ * patterns, similar to date time pattern in SimpleDateFormat.
+ *
+ * <P>
+ * Logically, the interval patterns are mappings
+ * from (skeleton, the_largest_different_calendar_field)
+ * to (date_interval_pattern).
+ *
+ * <P>
+ * A skeleton
+ * <ol>
+ * <li>
+ * only keeps the field pattern letter and ignores all other parts
+ * in a pattern, such as space, punctuations, and string literals.
+ * </li>
+ * <li>
+ * hides the order of fields.
+ * </li>
+ * <li>
+ * might hide a field's pattern letter length.
+ * </li>
+ * </ol>
+ *
+ * For those non-digit calendar fields, the pattern letter length is
+ * important, such as MMM, MMMM, and MMMMM; EEE and EEEE,
+ * and the field's pattern letter length is honored.
+ *
+ * For the digit calendar fields, such as M or MM, d or dd, yy or yyyy,
+ * the field pattern length is ignored and the best match, which is defined
+ * in date time patterns, will be returned without honor the field pattern
+ * letter length in skeleton.
+ *
+ * <P>
+ * The calendar fields we support for interval formatting are:
+ * year, month, date, day-of-week, am-pm, hour, hour-of-day, and minute.
+ * Those calendar fields can be defined in the following order:
+ * year > month > date > hour (in day) > minute
+ *
+ * The largest different calendar fields between 2 calendars is the
+ * first different calendar field in above order.
+ *
+ * For example: the largest different calendar fields between "Jan 10, 2007"
+ * and "Feb 20, 2008" is year.
+ *
+ * <P>
+ * For other calendar fields, the compact interval formatting is not
+ * supported. And the interval format will be fall back to fall-back
+ * patterns, which is mostly "{date0} - {date1}".
+ *
+ * <P>
+ * There is a set of pre-defined static skeleton strings.
+ * There are pre-defined interval patterns for those pre-defined skeletons
+ * in locales' resource files.
+ * For example, for a skeleton UDAT_YEAR_ABBR_MONTH_DAY, which is "yMMMd",
+ * in en_US, if the largest different calendar field between date1 and date2
+ * is "year", the date interval pattern is "MMM d, yyyy - MMM d, yyyy",
+ * such as "Jan 10, 2007 - Jan 10, 2008".
+ * If the largest different calendar field between date1 and date2 is "month",
+ * the date interval pattern is "MMM d - MMM d, yyyy",
+ * such as "Jan 10 - Feb 10, 2007".
+ * If the largest different calendar field between date1 and date2 is "day",
+ * the date interval pattern is ""MMM d-d, yyyy", such as "Jan 10-20, 2007".
+ *
+ * For date skeleton, the interval patterns when year, or month, or date is
+ * different are defined in resource files.
+ * For time skeleton, the interval patterns when am/pm, or hour, or minute is
+ * different are defined in resource files.
+ *
+ * <P>
+ * If a skeleton is not found in a locale's DateIntervalInfo, which means
+ * the interval patterns for the skeleton is not defined in resource file,
+ * the interval pattern will falls back to the interval "fallback" pattern
+ * defined in resource file.
+ * If the interval "fallback" pattern is not defined, the default fall-back
+ * is "{date0} - {data1}".
+ *
+ * <P>
+ * For the combination of date and time,
+ * The rule to generate interval patterns are:
+ * <ol>
+ * <li>
+ * when the year, month, or day differs, falls back to fall-back
+ * interval pattern, which mostly is the concatenate the two original
+ * expressions with a separator between,
+ * For example, interval pattern from "Jan 10, 2007 10:10 am"
+ * to "Jan 11, 2007 10:10am" is
+ * "Jan 10, 2007 10:10 am - Jan 11, 2007 10:10am"
+ * </li>
+ * <li>
+ * otherwise, present the date followed by the range expression
+ * for the time.
+ * For example, interval pattern from "Jan 10, 2007 10:10 am"
+ * to "Jan 10, 2007 11:10am" is "Jan 10, 2007 10:10 am - 11:10am"
+ * </li>
+ * </ol>
+ *
+ *
+ * <P>
+ * If two dates are the same, the interval pattern is the single date pattern.
+ * For example, interval pattern from "Jan 10, 2007" to "Jan 10, 2007" is
+ * "Jan 10, 2007".
+ *
+ * Or if the presenting fields between 2 dates have the exact same values,
+ * the interval pattern is the single date pattern.
+ * For example, if user only requests year and month,
+ * the interval pattern from "Jan 10, 2007" to "Jan 20, 2007" is "Jan 2007".
+ *
+ * <P>
+ * DateIntervalFormat needs the following information for correct
+ * formatting: time zone, calendar type, pattern, date format symbols,
+ * and date interval patterns.
+ * It can be instantiated in 2 ways:
+ * <ol>
+ * <li>
+ * create an instance using default or given locale plus given skeleton.
+ * Users are encouraged to created date interval formatter this way and
+ * to use the pre-defined skeleton macros, such as
+ * UDAT_YEAR_NUM_MONTH, which consists the calendar fields and
+ * the format style.
+ * </li>
+ * <li>
+ * create an instance using default or given locale plus given skeleton
+ * plus a given DateIntervalInfo.
+ * This factory method is for powerful users who want to provide their own
+ * interval patterns.
+ * Locale provides the timezone, calendar, and format symbols information.
+ * Local plus skeleton provides full pattern information.
+ * DateIntervalInfo provides the date interval patterns.
+ * </li>
+ * </ol>
+ *
+ * <P>
+ * For the calendar field pattern letter, such as G, y, M, d, a, h, H, m, s etc.
+ * DateIntervalFormat uses the same syntax as that of
+ * DateTime format.
+ *
+ * <P>
+ * Code Sample: general usage
+ * <pre>
+ * \code
+ * // the date interval object which the DateIntervalFormat formats on
+ * // and parses into
+ * DateInterval* dtInterval = new DateInterval(1000*3600*24, 1000*3600*24*2);
+ * UErrorCode status = U_ZERO_ERROR;
+ * DateIntervalFormat* dtIntervalFmt = DateIntervalFormat::createInstance(
+ * UDAT_YEAR_MONTH_DAY,
+ * Locale("en", "GB", ""), status);
+ * UnicodeUnicodeString dateIntervalString;
+ * FieldPosition pos = 0;
+ * // formatting
+ * dtIntervalFmt->format(dtInterval, dateIntervalUnicodeString, pos, status);
+ * delete dtIntervalFmt;
+ * \endcode
+ * </pre>
+ */
+
+class U_I18N_API DateIntervalFormat : public Format {
+public:
+
+ /**
+ * Construct a DateIntervalFormat from skeleton and the default locale.
+ *
+ * This is a convenient override of
+ * createInstance(const UnicodeString& skeleton, const Locale& locale,
+ * UErrorCode&)
+ * with the value of locale as default locale.
+ *
+ * @param skeleton the skeleton on which interval format based.
+ * @param status output param set to success/failure code on exit
+ * @return a date time interval formatter which the caller owns.
+ * @stable ICU 4.0
+ */
+ static DateIntervalFormat* U_EXPORT2 createInstance(
+ const UnicodeString& skeleton,
+ UErrorCode& status);
+
+ /**
+ * Construct a DateIntervalFormat from skeleton and a given locale.
+ * <P>
+ * In this factory method,
+ * the date interval pattern information is load from resource files.
+ * Users are encouraged to created date interval formatter this way and
+ * to use the pre-defined skeleton macros.
+ *
+ * <P>
+ * There are pre-defined skeletons (defined in udate.h) having predefined
+ * interval patterns in resource files.
+ * Users are encouraged to use those macros.
+ * For example:
+ * DateIntervalFormat::createInstance(UDAT_MONTH_DAY, status)
+ *
+ * The given Locale provides the interval patterns.
+ * For example, for en_GB, if skeleton is UDAT_YEAR_ABBR_MONTH_WEEKDAY_DAY,
+ * which is "yMMMEEEd",
+ * the interval patterns defined in resource file to above skeleton are:
+ * "EEE, d MMM, yyyy - EEE, d MMM, yyyy" for year differs,
+ * "EEE, d MMM - EEE, d MMM, yyyy" for month differs,
+ * "EEE, d - EEE, d MMM, yyyy" for day differs,
+ * @param skeleton the skeleton on which interval format based.
+ * @param locale the given locale
+ * @param status output param set to success/failure code on exit
+ * @return a date time interval formatter which the caller owns.
+ * @stable ICU 4.0
+ */
+
+ static DateIntervalFormat* U_EXPORT2 createInstance(
+ const UnicodeString& skeleton,
+ const Locale& locale,
+ UErrorCode& status);
+
+ /**
+ * Construct a DateIntervalFormat from skeleton
+ * DateIntervalInfo, and default locale.
+ *
+ * This is a convenient override of
+ * createInstance(const UnicodeString& skeleton, const Locale& locale,
+ * const DateIntervalInfo& dtitvinf, UErrorCode&)
+ * with the locale value as default locale.
+ *
+ * @param skeleton the skeleton on which interval format based.
+ * @param dtitvinf the DateIntervalInfo object.
+ * @param status output param set to success/failure code on exit
+ * @return a date time interval formatter which the caller owns.
+ * @stable ICU 4.0
+ */
+ static DateIntervalFormat* U_EXPORT2 createInstance(
+ const UnicodeString& skeleton,
+ const DateIntervalInfo& dtitvinf,
+ UErrorCode& status);
+
+ /**
+ * Construct a DateIntervalFormat from skeleton
+ * a DateIntervalInfo, and the given locale.
+ *
+ * <P>
+ * In this factory method, user provides its own date interval pattern
+ * information, instead of using those pre-defined data in resource file.
+ * This factory method is for powerful users who want to provide their own
+ * interval patterns.
+ * <P>
+ * There are pre-defined skeletons (defined in udate.h) having predefined
+ * interval patterns in resource files.
+ * Users are encouraged to use those macros.
+ * For example:
+ * DateIntervalFormat::createInstance(UDAT_MONTH_DAY, status)
+ *
+ * The DateIntervalInfo provides the interval patterns.
+ * and the DateIntervalInfo ownership remains to the caller.
+ *
+ * User are encouraged to set default interval pattern in DateIntervalInfo
+ * as well, if they want to set other interval patterns ( instead of
+ * reading the interval patterns from resource files).
+ * When the corresponding interval pattern for a largest calendar different
+ * field is not found ( if user not set it ), interval format fallback to
+ * the default interval pattern.
+ * If user does not provide default interval pattern, it fallback to
+ * "{date0} - {date1}"
+ *
+ * @param skeleton the skeleton on which interval format based.
+ * @param locale the given locale
+ * @param dtitvinf the DateIntervalInfo object.
+ * @param status output param set to success/failure code on exit
+ * @return a date time interval formatter which the caller owns.
+ * @stable ICU 4.0
+ */
+ static DateIntervalFormat* U_EXPORT2 createInstance(
+ const UnicodeString& skeleton,
+ const Locale& locale,
+ const DateIntervalInfo& dtitvinf,
+ UErrorCode& status);
+
+ /**
+ * Destructor.
+ * @stable ICU 4.0
+ */
+ virtual ~DateIntervalFormat();
+
+ /**
+ * Clone this Format object polymorphically. The caller owns the result and
+ * should delete it when done.
+ * @return A copy of the object.
+ * @stable ICU 4.0
+ */
+ virtual Format* clone(void) const;
+
+ /**
+ * Return true if the given Format objects are semantically equal. Objects
+ * of different subclasses are considered unequal.
+ * @param other the object to be compared with.
+ * @return true if the given Format objects are semantically equal.
+ * @stable ICU 4.0
+ */
+ virtual UBool operator==(const Format& other) const;
+
+ /**
+ * Return true if the given Format objects are not semantically equal.
+ * Objects of different subclasses are considered unequal.
+ * @param other the object to be compared with.
+ * @return true if the given Format objects are not semantically equal.
+ * @stable ICU 4.0
+ */
+ UBool operator!=(const Format& other) const;
+
+ /**
+ * Format an object to produce a string. This method handles Formattable
+ * objects with a DateInterval type.
+ * If a the Formattable object type is not a DateInterval,
+ * then it returns a failing UErrorCode.
+ *
+ * @param obj The object to format.
+ * Must be a DateInterval.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param fieldPosition On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @param status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 4.0
+ */
+ virtual UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition,
+ UErrorCode& status) const ;
+
+
+
+ /**
+ * Format a DateInterval to produce a string.
+ *
+ * @param dtInterval DateInterval to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param fieldPosition On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @param status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 4.0
+ */
+ UnicodeString& format(const DateInterval* dtInterval,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition,
+ UErrorCode& status) const ;
+
+
+ /**
+ * Format 2 Calendars to produce a string.
+ *
+ * Note: "fromCalendar" and "toCalendar" are not const,
+ * since calendar is not const in SimpleDateFormat::format(Calendar&),
+ *
+ * @param fromCalendar calendar set to the from date in date interval
+ * to be formatted into date interval string
+ * @param toCalendar calendar set to the to date in date interval
+ * to be formatted into date interval string
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param fieldPosition On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @param status Output param filled with success/failure status.
+ * Caller needs to make sure it is SUCCESS
+ * at the function entrance
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 4.0
+ */
+ UnicodeString& format(Calendar& fromCalendar,
+ Calendar& toCalendar,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition,
+ UErrorCode& status) const ;
+
+ /**
+ * Date interval parsing is not supported. Please do not use.
+ * <P>
+ * This method should handle parsing of
+ * date time interval strings into Formattable objects with
+ * DateInterval type, which is a pair of UDate.
+ * <P>
+ * Before calling, set parse_pos.index to the offset you want to start
+ * parsing at in the source. After calling, parse_pos.index is the end of
+ * the text you parsed. If error occurs, index is unchanged.
+ * <P>
+ * When parsing, leading whitespace is discarded (with a successful parse),
+ * while trailing whitespace is left as is.
+ * <P>
+ * See Format::parseObject() for more.
+ *
+ * @param source The string to be parsed into an object.
+ * @param result Formattable to be set to the parse result.
+ * If parse fails, return contents are undefined.
+ * @param parse_pos The position to start parsing at. Since no parsing
+ * is supported, upon return this param is unchanged.
+ * @return A newly created Formattable* object, or NULL
+ * on failure. The caller owns this and should
+ * delete it when done.
+ * @internal ICU 4.0
+ */
+ virtual void parseObject(const UnicodeString& source,
+ Formattable& result,
+ ParsePosition& parse_pos) const;
+
+
+ /**
+ * Gets the date time interval patterns.
+ * @return the date time interval patterns associated with
+ * this date interval formatter.
+ * @stable ICU 4.0
+ */
+ const DateIntervalInfo* getDateIntervalInfo(void) const;
+
+
+ /**
+ * Set the date time interval patterns.
+ * @param newIntervalPatterns the given interval patterns to copy.
+ * @param status output param set to success/failure code on exit
+ * @stable ICU 4.0
+ */
+ void setDateIntervalInfo(const DateIntervalInfo& newIntervalPatterns,
+ UErrorCode& status);
+
+
+ /**
+ * Gets the date formatter
+ * @return the date formatter associated with this date interval formatter.
+ * @stable ICU 4.0
+ */
+ const DateFormat* getDateFormat(void) const;
+
+ /**
+ * Return the class ID for this class. This is useful only for comparing to
+ * a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . erived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @stable ICU 4.0
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * 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 4.0
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+protected:
+
+ /**
+ * Copy constructor.
+ * @stable ICU 4.0
+ */
+ DateIntervalFormat(const DateIntervalFormat&);
+
+ /**
+ * Assignment operator.
+ * @stable ICU 4.0
+ */
+ DateIntervalFormat& operator=(const DateIntervalFormat&);
+
+private:
+
+ /*
+ * This is for ICU internal use only. Please do not use.
+ * Save the interval pattern information.
+ * Interval pattern consists of 2 single date patterns and the separator.
+ * For example, interval pattern "MMM d - MMM d, yyyy" consists
+ * a single date pattern "MMM d", another single date pattern "MMM d, yyyy",
+ * and a separator "-".
+ * The pattern is divided into 2 parts. For above example,
+ * the first part is "MMM d - ", and the second part is "MMM d, yyyy".
+ * Also, the first date appears in an interval pattern could be
+ * the earlier date or the later date.
+ * And such information is saved in the interval pattern as well.
+ * @internal ICU 4.0
+ */
+ struct PatternInfo {
+ UnicodeString firstPart;
+ UnicodeString secondPart;
+ /**
+ * Whether the first date in interval pattern is later date or not.
+ * Fallback format set the default ordering.
+ * And for a particular interval pattern, the order can be
+ * overriden by prefixing the interval pattern with "latestFirst:" or
+ * "earliestFirst:"
+ * For example, given 2 date, Jan 10, 2007 to Feb 10, 2007.
+ * if the fallback format is "{0} - {1}",
+ * and the pattern is "d MMM - d MMM yyyy", the interval format is
+ * "10 Jan - 10 Feb, 2007".
+ * If the pattern is "latestFirst:d MMM - d MMM yyyy",
+ * the interval format is "10 Feb - 10 Jan, 2007"
+ */
+ UBool laterDateFirst;
+ };
+
+
+ /**
+ * default constructor
+ * @internal ICU 4.0
+ */
+ DateIntervalFormat();
+
+ /**
+ * Construct a DateIntervalFormat from DateFormat,
+ * a DateIntervalInfo, and skeleton.
+ * DateFormat provides the timezone, calendar,
+ * full pattern, and date format symbols information.
+ * It should be a SimpleDateFormat object which
+ * has a pattern in it.
+ * the DateIntervalInfo provides the interval patterns.
+ *
+ * Note: the DateIntervalFormat takes ownership of both
+ * DateFormat and DateIntervalInfo objects.
+ * Caller should not delete them.
+ *
+ * @param locale the locale of this date interval formatter.
+ * @param dtitvinf the DateIntervalInfo object to be adopted.
+ * @param skeleton the skeleton of the date formatter
+ * @param status output param set to success/failure code on exit
+ * @internal ICU 4.0
+ */
+ DateIntervalFormat(const Locale& locale, DateIntervalInfo* dtItvInfo,
+ const UnicodeString* skeleton, UErrorCode& status);
+
+
+ /**
+ * Construct a DateIntervalFormat from DateFormat
+ * and a DateIntervalInfo.
+ *
+ * It is a wrapper of the constructor.
+ *
+ * @param locale the locale of this date interval formatter.
+ * @param dtitvinf the DateIntervalInfo object to be adopted.
+ * @param skeleton the skeleton of this formatter.
+ * @param status Output param set to success/failure code.
+ * @return a date time interval formatter which the caller owns.
+ * @internal ICU 4.0
+ */
+ static DateIntervalFormat* U_EXPORT2 create(const Locale& locale,
+ DateIntervalInfo* dtitvinf,
+ const UnicodeString* skeleton,
+ UErrorCode& status);
+
+ /**
+ * Create a simple date/time formatter from skeleton, given locale,
+ * and date time pattern generator.
+ *
+ * @param skeleton the skeleton on which date format based.
+ * @param locale the given locale.
+ * @param dtpng the date time pattern generator.
+ * @param status Output param to be set to success/failure code.
+ * If it is failure, the returned date formatter will
+ * be NULL.
+ * @return a simple date formatter which the caller owns.
+ * @internal ICU 4.0
+ */
+ static SimpleDateFormat* U_EXPORT2 createSDFPatternInstance(
+ const UnicodeString& skeleton,
+ const Locale& locale,
+ DateTimePatternGenerator* dtpng,
+ UErrorCode& status);
+
+
+ /**
+ * Below are for generating interval patterns local to the formatter
+ */
+
+
+ /**
+ * Format 2 Calendars using fall-back interval pattern
+ *
+ * The full pattern used in this fall-back format is the
+ * full pattern of the date formatter.
+ *
+ * @param fromCalendar calendar set to the from date in date interval
+ * to be formatted into date interval string
+ * @param toCalendar calendar set to the to date in date interval
+ * to be formatted into date interval string
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @param status output param set to success/failure code on exit
+ * @return Reference to 'appendTo' parameter.
+ * @internal ICU 4.0
+ */
+ UnicodeString& fallbackFormat(Calendar& fromCalendar,
+ Calendar& toCalendar,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+
+
+
+ /**
+ * Initialize interval patterns locale to this formatter
+ *
+ * This code is a bit complicated since
+ * 1. the interval patterns saved in resource bundle files are interval
+ * patterns based on date or time only.
+ * It does not have interval patterns based on both date and time.
+ * Interval patterns on both date and time are algorithm generated.
+ *
+ * For example, it has interval patterns on skeleton "dMy" and "hm",
+ * but it does not have interval patterns on skeleton "dMyhm".
+ *
+ * The rule to generate interval patterns for both date and time skeleton are
+ * 1) when the year, month, or day differs, concatenate the two original
+ * expressions with a separator between,
+ * For example, interval pattern from "Jan 10, 2007 10:10 am"
+ * to "Jan 11, 2007 10:10am" is
+ * "Jan 10, 2007 10:10 am - Jan 11, 2007 10:10am"
+ *
+ * 2) otherwise, present the date followed by the range expression
+ * for the time.
+ * For example, interval pattern from "Jan 10, 2007 10:10 am"
+ * to "Jan 10, 2007 11:10am" is
+ * "Jan 10, 2007 10:10 am - 11:10am"
+ *
+ * 2. even a pattern does not request a certain calendar field,
+ * the interval pattern needs to include such field if such fields are
+ * different between 2 dates.
+ * For example, a pattern/skeleton is "hm", but the interval pattern
+ * includes year, month, and date when year, month, and date differs.
+ *
+ *
+ * @param status output param set to success/failure code on exit
+ * @internal ICU 4.0
+ */
+ void initializePattern(UErrorCode& status);
+
+
+
+ /**
+ * Set fall back interval pattern given a calendar field,
+ * a skeleton, and a date time pattern generator.
+ * @param field the largest different calendar field
+ * @param skeleton a skeleton
+ * @param status output param set to success/failure code on exit
+ * @internal ICU 4.0
+ */
+ void setFallbackPattern(UCalendarDateFields field,
+ const UnicodeString& skeleton,
+ UErrorCode& status);
+
+
+
+ /**
+ * get separated date and time skeleton from a combined skeleton.
+ *
+ * The difference between date skeleton and normalizedDateSkeleton are:
+ * 1. both 'y' and 'd' are appeared only once in normalizeDateSkeleton
+ * 2. 'E' and 'EE' are normalized into 'EEE'
+ * 3. 'MM' is normalized into 'M'
+ *
+ ** the difference between time skeleton and normalizedTimeSkeleton are:
+ * 1. both 'H' and 'h' are normalized as 'h' in normalized time skeleton,
+ * 2. 'a' is omitted in normalized time skeleton.
+ * 3. there is only one appearance for 'h', 'm','v', 'z' in normalized time
+ * skeleton
+ *
+ *
+ * @param skeleton given combined skeleton.
+ * @param date Output parameter for date only skeleton.
+ * @param normalizedDate Output parameter for normalized date only
+ *
+ * @param time Output parameter for time only skeleton.
+ * @param normalizedTime Output parameter for normalized time only
+ * skeleton.
+ *
+ * @internal ICU 4.0
+ */
+ static void U_EXPORT2 getDateTimeSkeleton(const UnicodeString& skeleton,
+ UnicodeString& date,
+ UnicodeString& normalizedDate,
+ UnicodeString& time,
+ UnicodeString& normalizedTime);
+
+
+
+ /**
+ * Generate date or time interval pattern from resource,
+ * and set them into the interval pattern locale to this formatter.
+ *
+ * It needs to handle the following:
+ * 1. need to adjust field width.
+ * For example, the interval patterns saved in DateIntervalInfo
+ * includes "dMMMy", but not "dMMMMy".
+ * Need to get interval patterns for dMMMMy from dMMMy.
+ * Another example, the interval patterns saved in DateIntervalInfo
+ * includes "hmv", but not "hmz".
+ * Need to get interval patterns for "hmz' from 'hmv'
+ *
+ * 2. there might be no pattern for 'y' differ for skeleton "Md",
+ * in order to get interval patterns for 'y' differ,
+ * need to look for it from skeleton 'yMd'
+ *
+ * @param dateSkeleton normalized date skeleton
+ * @param timeSkeleton normalized time skeleton
+ * @return whether the resource is found for the skeleton.
+ * TRUE if interval pattern found for the skeleton,
+ * FALSE otherwise.
+ * @internal ICU 4.0
+ */
+ UBool setSeparateDateTimePtn(const UnicodeString& dateSkeleton,
+ const UnicodeString& timeSkeleton);
+
+
+
+
+ /**
+ * Generate interval pattern from existing resource
+ *
+ * It not only save the interval patterns,
+ * but also return the extended skeleton and its best match skeleton.
+ *
+ * @param field largest different calendar field
+ * @param skeleton skeleton
+ * @param bestSkeleton the best match skeleton which has interval pattern
+ * defined in resource
+ * @param differenceInfo the difference between skeleton and best skeleton
+ * 0 means the best matched skeleton is the same as input skeleton
+ * 1 means the fields are the same, but field width are different
+ * 2 means the only difference between fields are v/z,
+ * -1 means there are other fields difference
+ *
+ * @param extendedSkeleton extended skeleton
+ * @param extendedBestSkeleton extended best match skeleton
+ * @return whether the interval pattern is found
+ * through extending skeleton or not.
+ * TRUE if interval pattern is found by
+ * extending skeleton, FALSE otherwise.
+ * @internal ICU 4.0
+ */
+ UBool setIntervalPattern(UCalendarDateFields field,
+ const UnicodeString* skeleton,
+ const UnicodeString* bestSkeleton,
+ int8_t differenceInfo,
+ UnicodeString* extendedSkeleton = NULL,
+ UnicodeString* extendedBestSkeleton = NULL);
+
+ /**
+ * Adjust field width in best match interval pattern to match
+ * the field width in input skeleton.
+ *
+ * TODO (xji) make a general solution
+ * The adjusting rule can be:
+ * 1. always adjust
+ * 2. never adjust
+ * 3. default adjust, which means adjust according to the following rules
+ * 3.1 always adjust string, such as MMM and MMMM
+ * 3.2 never adjust between string and numeric, such as MM and MMM
+ * 3.3 always adjust year
+ * 3.4 do not adjust 'd', 'h', or 'm' if h presents
+ * 3.5 do not adjust 'M' if it is numeric(?)
+ *
+ * Since date interval format is well-formed format,
+ * date and time skeletons are normalized previously,
+ * till this stage, the adjust here is only "adjust strings, such as MMM
+ * and MMMM, EEE and EEEE.
+ *
+ * @param inputSkeleton the input skeleton
+ * @param bestMatchSkeleton the best match skeleton
+ * @param bestMatchIntervalpattern the best match interval pattern
+ * @param differenceInfo the difference between 2 skeletons
+ * 1 means only field width differs
+ * 2 means v/z exchange
+ * @param adjustedIntervalPattern adjusted interval pattern
+ * @internal ICU 4.0
+ */
+ static void U_EXPORT2 adjustFieldWidth(
+ const UnicodeString& inputSkeleton,
+ const UnicodeString& bestMatchSkeleton,
+ const UnicodeString& bestMatchIntervalPattern,
+ int8_t differenceInfo,
+ UnicodeString& adjustedIntervalPattern);
+
+ /**
+ * Concat a single date pattern with a time interval pattern,
+ * set it into the intervalPatterns, while field is time field.
+ * This is used to handle time interval patterns on skeleton with
+ * both time and date. Present the date followed by
+ * the range expression for the time.
+ * @param format date and time format
+ * @param formatLen format string length
+ * @param datePattern date pattern
+ * @param field time calendar field: AM_PM, HOUR, MINUTE
+ * @param status output param set to success/failure code on exit
+ * @internal ICU 4.0
+ */
+ void concatSingleDate2TimeInterval(const UChar* format,
+ int32_t formatLen,
+ const UnicodeString& datePattern,
+ UCalendarDateFields field,
+ UErrorCode& status);
+
+ /**
+ * check whether a calendar field present in a skeleton.
+ * @param field calendar field need to check
+ * @param skeleton given skeleton on which to check the calendar field
+ * @return true if field present in a skeleton.
+ * @internal ICU 4.0
+ */
+ static UBool U_EXPORT2 fieldExistsInSkeleton(UCalendarDateFields field,
+ const UnicodeString& skeleton);
+
+
+ /**
+ * Split interval patterns into 2 part.
+ * @param intervalPattern interval pattern
+ * @return the index in interval pattern which split the pattern into 2 part
+ * @internal ICU 4.0
+ */
+ static int32_t U_EXPORT2 splitPatternInto2Part(const UnicodeString& intervalPattern);
+
+
+ /**
+ * Break interval patterns as 2 part and save them into pattern info.
+ * @param field calendar field
+ * @param intervalPattern interval pattern
+ * @internal ICU 4.0
+ */
+ void setIntervalPattern(UCalendarDateFields field,
+ const UnicodeString& intervalPattern);
+
+
+ /**
+ * Break interval patterns as 2 part and save them into pattern info.
+ * @param field calendar field
+ * @param intervalPattern interval pattern
+ * @param laterDateFirst whether later date appear first in interval pattern
+ * @internal ICU 4.0
+ */
+ void setIntervalPattern(UCalendarDateFields field,
+ const UnicodeString& intervalPattern,
+ UBool laterDateFirst);
+
+
+ /**
+ * Set pattern information.
+ *
+ * @param field calendar field
+ * @param firstPart the first part in interval pattern
+ * @param secondPart the second part in interval pattern
+ * @param laterDateFirst whether the first date in intervalPattern
+ * is earlier date or later date
+ * @internal ICU 4.0
+ */
+ void setPatternInfo(UCalendarDateFields field,
+ const UnicodeString* firstPart,
+ const UnicodeString* secondpart,
+ UBool laterDateFirst);
+
+
+ // from calendar field to pattern letter
+ static const UChar fgCalendarFieldToPatternLetter[];
+
+
+ /**
+ * The interval patterns for this locale.
+ */
+ DateIntervalInfo* fInfo;
+
+ /**
+ * The DateFormat object used to format single pattern
+ */
+ SimpleDateFormat* fDateFormat;
+
+ /**
+ * The 2 calendars with the from and to date.
+ * could re-use the calendar in fDateFormat,
+ * but keeping 2 calendars make it clear and clean.
+ */
+ Calendar* fFromCalendar;
+ Calendar* fToCalendar;
+
+ /**
+ * Date time pattern generator
+ */
+ DateTimePatternGenerator* fDtpng;
+
+ /**
+ * Following are interval information relavent (locale) to this formatter.
+ */
+ UnicodeString fSkeleton;
+ PatternInfo fIntervalPatterns[DateIntervalInfo::kIPI_MAX_INDEX];
+};
+
+
+
+
+
+
+inline UBool
+DateIntervalFormat::operator!=(const Format& other) const {
+ return !operator==(other);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _DTITVFMT_H__
+//eof
Modified: trunk/source/i18n/unicode/dtitvinf.h
===================================================================
--- trunk/source/i18n/unicode/dtitvinf.h 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/i18n/unicode/dtitvinf.h 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,528 +1,528 @@
-/*
- *******************************************************************************
- * Copyright (C) 2008-2009, International Business Machines Corporation and
- * others. All Rights Reserved.
- *******************************************************************************
- *
- * File DTITVINF.H
- *
- *******************************************************************************
- */
-
-#ifndef __DTITVINF_H__
-#define __DTITVINF_H__
-
-#include "unicode/utypes.h"
-
-/**
- * \file
- * \brief C++ API: Date/Time interval patterns for formatting date/time interval
- */
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/udat.h"
-#include "unicode/locid.h"
-#include "unicode/ucal.h"
-#include "unicode/dtptngen.h"
-//#include "dtitv_impl.h"
-
-/**
- * @internal ICU 4.0
- */
-
-union UHashTok;
-
-
-U_NAMESPACE_BEGIN
-
-U_CDECL_BEGIN
-
-/**
- * @internal ICU 4.0
- */
-UBool U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2) ;
-
-U_CDECL_END
-
-
-/**
- * DateIntervalInfo is a public class for encapsulating localizable
- * date time interval patterns. It is used by DateIntervalFormat.
- *
- * <P>
- * For most users, ordinary use of DateIntervalFormat does not need to create
- * DateIntervalInfo object directly.
- * DateIntervalFormat will take care of it when creating a date interval
- * formatter when user pass in skeleton and locale.
- *
- * <P>
- * For power users, who want to create their own date interval patterns,
- * or want to re-set date interval patterns, they could do so by
- * directly creating DateIntervalInfo and manupulating it.
- *
- * <P>
- * Logically, the interval patterns are mappings
- * from (skeleton, the_largest_different_calendar_field)
- * to (date_interval_pattern).
- *
- * <P>
- * A skeleton
- * <ol>
- * <li>
- * only keeps the field pattern letter and ignores all other parts
- * in a pattern, such as space, punctuations, and string literals.
- * <li>
- * hides the order of fields.
- * <li>
- * might hide a field's pattern letter length.
- *
- * For those non-digit calendar fields, the pattern letter length is
- * important, such as MMM, MMMM, and MMMMM; EEE and EEEE,
- * and the field's pattern letter length is honored.
- *
- * For the digit calendar fields, such as M or MM, d or dd, yy or yyyy,
- * the field pattern length is ignored and the best match, which is defined
- * in date time patterns, will be returned without honor the field pattern
- * letter length in skeleton.
- * </ol>
- *
- * <P>
- * The calendar fields we support for interval formatting are:
- * year, month, date, day-of-week, am-pm, hour, hour-of-day, and minute.
- * Those calendar fields can be defined in the following order:
- * year > month > date > am-pm > hour > minute
- *
- * The largest different calendar fields between 2 calendars is the
- * first different calendar field in above order.
- *
- * For example: the largest different calendar fields between "Jan 10, 2007"
- * and "Feb 20, 2008" is year.
- *
- * <P>
- * There is a set of pre-defined static skeleton strings.
- * There are pre-defined interval patterns for those pre-defined skeletons
- * in locales' resource files.
- * For example, for a skeleton UDAT_YEAR_ABBR_MONTH_DAY, which is "yMMMd",
- * in en_US, if the largest different calendar field between date1 and date2
- * is "year", the date interval pattern is "MMM d, yyyy - MMM d, yyyy",
- * such as "Jan 10, 2007 - Jan 10, 2008".
- * If the largest different calendar field between date1 and date2 is "month",
- * the date interval pattern is "MMM d - MMM d, yyyy",
- * such as "Jan 10 - Feb 10, 2007".
- * If the largest different calendar field between date1 and date2 is "day",
- * the date interval pattern is ""MMM d-d, yyyy", such as "Jan 10-20, 2007".
- *
- * For date skeleton, the interval patterns when year, or month, or date is
- * different are defined in resource files.
- * For time skeleton, the interval patterns when am/pm, or hour, or minute is
- * different are defined in resource files.
- *
- *
- * <P>
- * There are 2 dates in interval pattern. For most locales, the first date
- * in an interval pattern is the earlier date. There might be a locale in which
- * the first date in an interval pattern is the later date.
- * We use fallback format for the default order for the locale.
- * For example, if the fallback format is "{0} - {1}", it means
- * the first date in the interval pattern for this locale is earlier date.
- * If the fallback format is "{1} - {0}", it means the first date is the
- * later date.
- * For a particular interval pattern, the default order can be overriden
- * by prefixing "latestFirst:" or "earliestFirst:" to the interval pattern.
- * For example, if the fallback format is "{0}-{1}",
- * but for skeleton "yMMMd", the interval pattern when day is different is
- * "latestFirst:d-d MMM yy", it means by default, the first date in interval
- * pattern is the earlier date. But for skeleton "yMMMd", when day is different,
- * the first date in "d-d MMM yy" is the later date.
- *
- * <P>
- * The recommended way to create a DateIntervalFormat object is to pass in
- * the locale.
- * By using a Locale parameter, the DateIntervalFormat object is
- * initialized with the pre-defined interval patterns for a given or
- * default locale.
- * <P>
- * Users can also create DateIntervalFormat object
- * by supplying their own interval patterns.
- * It provides flexibility for power users.
- *
- * <P>
- * After a DateIntervalInfo object is created, clients may modify
- * the interval patterns using setIntervalPattern function as so desired.
- * Currently, users can only set interval patterns when the following
- * calendar fields are different: ERA, YEAR, MONTH, DATE, DAY_OF_MONTH,
- * DAY_OF_WEEK, AM_PM, HOUR, HOUR_OF_DAY, and MINUTE.
- * Interval patterns when other calendar fields are different is not supported.
- * <P>
- * DateIntervalInfo objects are cloneable.
- * When clients obtain a DateIntervalInfo object,
- * they can feel free to modify it as necessary.
- * <P>
- * DateIntervalInfo are not expected to be subclassed.
- * Data for a calendar is loaded out of resource bundles.
- * To ICU 4.0, date interval patterns are only supported in Gregorian calendar.
- * @stable ICU 4.0
-**/
-
-class U_I18N_API DateIntervalInfo : public UObject {
-public:
- /**
- * Default constructor.
- * It does not initialize any interval patterns except
- * that it initialize default fall-back pattern as "{0} - {1}",
- * which can be reset by setFallbackIntervalPattern().
- * It should be followed by setFallbackIntervalPattern() and
- * setIntervalPattern(),
- * and is recommended to be used only for power users who
- * wants to create their own interval patterns and use them to create
- * date interval formatter.
- * @param status output param set to success/failure code on exit
- * @internal ICU 4.0
- */
- DateIntervalInfo(UErrorCode& status);
-
-
- /**
- * Construct DateIntervalInfo for the given locale,
- * @param locale the interval patterns are loaded from the Gregorian
- * calendar data in this locale.
- * @param status output param set to success/failure code on exit
- * @stable ICU 4.0
- */
- DateIntervalInfo(const Locale& locale, UErrorCode& status);
-
-
- /**
- * Copy constructor.
- * @stable ICU 4.0
- */
- DateIntervalInfo(const DateIntervalInfo&);
-
- /**
- * Assignment operator
- * @stable ICU 4.0
- */
- DateIntervalInfo& operator=(const DateIntervalInfo&);
-
- /**
- * Clone this object polymorphically.
- * The caller owns the result and should delete it when done.
- * @return a copy of the object
- * @stable ICU 4.0
- */
- virtual DateIntervalInfo* clone(void) const;
-
- /**
- * Destructor.
- * It is virtual to be safe, but it is not designed to be subclassed.
- * @stable ICU 4.0
- */
- virtual ~DateIntervalInfo();
-
-
- /**
- * Return true if another object is semantically equal to this one.
- *
- * @param other the DateIntervalInfo object to be compared with.
- * @return true if other is semantically equal to this.
- * @stable ICU 4.0
- */
- virtual UBool operator==(const DateIntervalInfo& other) const;
-
- /**
- * Return true if another object is semantically unequal to this one.
- *
- * @param other the DateIntervalInfo object to be compared with.
- * @return true if other is semantically unequal to this.
- * @stable ICU 4.0
- */
- UBool operator!=(const DateIntervalInfo& other) const;
-
-
-
- /**
- * Provides a way for client to build interval patterns.
- * User could construct DateIntervalInfo by providing a list of skeletons
- * and their patterns.
- * <P>
- * For example:
- * <pre>
- * UErrorCode status = U_ZERO_ERROR;
- * DateIntervalInfo dIntervalInfo = new DateIntervalInfo();
- * dIntervalInfo->setFallbackIntervalPattern("{0} ~ {1}");
- * dIntervalInfo->setIntervalPattern("yMd", UCAL_YEAR, "'from' yyyy-M-d 'to' yyyy-M-d", status);
- * dIntervalInfo->setIntervalPattern("yMMMd", UCAL_MONTH, "'from' yyyy MMM d 'to' MMM d", status);
- * dIntervalInfo->setIntervalPattern("yMMMd", UCAL_DAY, "yyyy MMM d-d", status, status);
- * </pre>
- *
- * Restriction:
- * Currently, users can only set interval patterns when the following
- * calendar fields are different: ERA, YEAR, MONTH, DATE, DAY_OF_MONTH,
- * DAY_OF_WEEK, AM_PM, HOUR, HOUR_OF_DAY, and MINUTE.
- * Interval patterns when other calendar fields are different are
- * not supported.
- *
- * @param skeleton the skeleton on which interval pattern based
- * @param lrgDiffCalUnit the largest different calendar unit.
- * @param intervalPattern the interval pattern on the largest different
- * calendar unit.
- * For example, if lrgDiffCalUnit is
- * "year", the interval pattern for en_US when year
- * is different could be "'from' yyyy 'to' yyyy".
- * @param status output param set to success/failure code on exit
- * @stable ICU 4.0
- */
- void setIntervalPattern(const UnicodeString& skeleton,
- UCalendarDateFields lrgDiffCalUnit,
- const UnicodeString& intervalPattern,
- UErrorCode& status);
-
- /**
- * Get the interval pattern given skeleton and
- * the largest different calendar field.
- * @param skeleton the skeleton
- * @param field the largest different calendar field
- * @param result output param to receive the pattern
- * @param status output param set to success/failure code on exit
- * @return a reference to 'result'
- * @stable ICU 4.0
- */
- UnicodeString& getIntervalPattern(const UnicodeString& skeleton,
- UCalendarDateFields field,
- UnicodeString& result,
- UErrorCode& status) const;
-
- /**
- * Get the fallback interval pattern.
- * @param result output param to receive the pattern
- * @return a reference to 'result'
- * @stable ICU 4.0
- */
- UnicodeString& getFallbackIntervalPattern(UnicodeString& result) const;
-
-
- /**
- * Re-set the fallback interval pattern.
- *
- * In construction, default fallback pattern is set as "{0} - {1}".
- * And constructor taking locale as parameter will set the
- * fallback pattern as what defined in the locale resource file.
- *
- * This method provides a way for user to replace the fallback pattern.
- *
- * @param fallbackPattern fall-back interval pattern.
- * @param status output param set to success/failure code on exit
- * @stable ICU 4.0
- */
- void setFallbackIntervalPattern(const UnicodeString& fallbackPattern,
- UErrorCode& status);
-
-
- /** Get default order -- whether the first date in pattern is later date
- or not.
- * return default date ordering in interval pattern. TRUE if the first date
- * in pattern is later date, FALSE otherwise.
- * @stable ICU 4.0
- */
- UBool getDefaultOrder() const;
-
-
- /**
- * ICU "poor man's RTTI", returns a UClassID for the actual class.
- *
- * @stable ICU 4.0
- */
- virtual UClassID getDynamicClassID() const;
-
- /**
- * ICU "poor man's RTTI", returns a UClassID for this class.
- *
- * @stable ICU 4.0
- */
- static UClassID U_EXPORT2 getStaticClassID();
-
-
-private:
- /**
- * DateIntervalFormat will need access to
- * getBestSkeleton(), parseSkeleton(), enum IntervalPatternIndex,
- * and calendarFieldToPatternIndex().
- *
- * Instead of making above public,
- * make DateIntervalFormat a friend of DateIntervalInfo.
- */
- friend class DateIntervalFormat;
-
- friend UBool U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2) ;
-
- /**
- * Following is for saving the interval patterns.
- * We only support interval patterns on
- * ERA, YEAR, MONTH, DAY, AM_PM, HOUR, and MINUTE
- */
- enum IntervalPatternIndex
- {
- kIPI_ERA,
- kIPI_YEAR,
- kIPI_MONTH,
- kIPI_DATE,
- kIPI_AM_PM,
- kIPI_HOUR,
- kIPI_MINUTE,
- kIPI_MAX_INDEX
- };
-
- /**
- * Initialize the DateIntervalInfo from locale
- * @param locale the given locale.
- * @param status output param set to success/failure code on exit
- * @internal ICU 4.0
- */
- void initializeData(const Locale& locale, UErrorCode& status);
-
-
- /* Set Interval pattern.
- *
- * It sets interval pattern into the hash map.
- *
- * @param skeleton skeleton on which the interval pattern based
- * @param lrgDiffCalUnit the largest different calendar unit.
- * @param intervalPattern the interval pattern on the largest different
- * calendar unit.
- * @param status output param set to success/failure code on exit
- * @internal ICU 4.0
- */
- void setIntervalPatternInternally(const UnicodeString& skeleton,
- UCalendarDateFields lrgDiffCalUnit,
- const UnicodeString& intervalPattern,
- UErrorCode& status);
-
-
- /**given an input skeleton, get the best match skeleton
- * which has pre-defined interval pattern in resource file.
- * Also return the difference between the input skeleton
- * and the best match skeleton.
- *
- * TODO (xji): set field weight or
- * isolate the funtionality in DateTimePatternGenerator
- * @param skeleton input skeleton
- * @param bestMatchDistanceInfo the difference between input skeleton
- * and best match skeleton.
- * 0, if there is exact match for input skeleton
- * 1, if there is only field width difference between
- * the best match and the input skeleton
- * 2, the only field difference is 'v' and 'z'
- * -1, if there is calendar field difference between
- * the best match and the input skeleton
- * @return best match skeleton
- * @internal ICU 4.0
- */
- const UnicodeString* getBestSkeleton(const UnicodeString& skeleton,
- int8_t& bestMatchDistanceInfo) const;
-
-
- /**
- * Parse skeleton, save each field's width.
- * It is used for looking for best match skeleton,
- * and adjust pattern field width.
- * @param skeleton skeleton to be parsed
- * @param skeletonFieldWidth parsed skeleton field width
- * @internal ICU 4.0
- */
- static void U_EXPORT2 parseSkeleton(const UnicodeString& skeleton,
- int32_t* skeletonFieldWidth);
-
-
- /**
- * Check whether one field width is numeric while the other is string.
- *
- * TODO (xji): make it general
- *
- * @param fieldWidth one field width
- * @param anotherFieldWidth another field width
- * @param patternLetter pattern letter char
- * @return true if one field width is numeric and the other is string,
- * false otherwise.
- * @internal ICU 4.0
- */
- static UBool U_EXPORT2 stringNumeric(int32_t fieldWidth,
- int32_t anotherFieldWidth,
- char patternLetter);
-
-
- /**
- * Convert calendar field to the interval pattern index in
- * hash table.
- *
- * Since we only support the following calendar fields:
- * ERA, YEAR, MONTH, DATE, DAY_OF_MONTH, DAY_OF_WEEK,
- * AM_PM, HOUR, HOUR_OF_DAY, and MINUTE,
- * We reserve only 4 interval patterns for a skeleton.
- *
- * @param field calendar field
- * @param status output param set to success/failure code on exit
- * @return interval pattern index in hash table
- * @internal ICU 4.0
- */
- static IntervalPatternIndex U_EXPORT2 calendarFieldToIntervalIndex(
- UCalendarDateFields field,
- UErrorCode& status);
-
-
- /**
- * delete hash table (of type fIntervalPatterns).
- *
- * @param hTable hash table to be deleted
- * @internal ICU 4.0
- */
- void deleteHash(Hashtable* hTable);
-
-
- /**
- * initialize hash table (of type fIntervalPatterns).
- *
- * @param status output param set to success/failure code on exit
- * @return hash table initialized
- * @internal ICU 4.0
- */
- Hashtable* initHash(UErrorCode& status);
-
-
-
- /**
- * copy hash table (of type fIntervalPatterns).
- *
- * @param source the source to copy from
- * @param target the target to copy to
- * @param status output param set to success/failure code on exit
- * @internal ICU 4.0
- */
- void copyHash(const Hashtable* source, Hashtable* target, UErrorCode& status);
-
-
- // data members
- // fallback interval pattern
- UnicodeString fFallbackIntervalPattern;
- // default order
- UBool fFirstDateInPtnIsLaterDate;
-
- // HashMap<UnicodeString, UnicodeString[kIPI_MAX_INDEX]>
- // HashMap( skeleton, pattern[largest_different_field] )
- Hashtable* fIntervalPatterns;
-
-};// end class DateIntervalInfo
-
-
-inline UBool
-DateIntervalInfo::operator!=(const DateIntervalInfo& other) const {
- return !operator==(other);
-}
-
-
-U_NAMESPACE_END
-
-#endif
-
-#endif
-
+/*
+ *******************************************************************************
+ * Copyright (C) 2008-2009, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ *******************************************************************************
+ *
+ * File DTITVINF.H
+ *
+ *******************************************************************************
+ */
+
+#ifndef __DTITVINF_H__
+#define __DTITVINF_H__
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Date/Time interval patterns for formatting date/time interval
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/udat.h"
+#include "unicode/locid.h"
+#include "unicode/ucal.h"
+#include "unicode/dtptngen.h"
+//#include "dtitv_impl.h"
+
+/**
+ * @internal ICU 4.0
+ */
+
+union UHashTok;
+
+
+U_NAMESPACE_BEGIN
+
+U_CDECL_BEGIN
+
+/**
+ * @internal ICU 4.0
+ */
+UBool U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2) ;
+
+U_CDECL_END
+
+
+/**
+ * DateIntervalInfo is a public class for encapsulating localizable
+ * date time interval patterns. It is used by DateIntervalFormat.
+ *
+ * <P>
+ * For most users, ordinary use of DateIntervalFormat does not need to create
+ * DateIntervalInfo object directly.
+ * DateIntervalFormat will take care of it when creating a date interval
+ * formatter when user pass in skeleton and locale.
+ *
+ * <P>
+ * For power users, who want to create their own date interval patterns,
+ * or want to re-set date interval patterns, they could do so by
+ * directly creating DateIntervalInfo and manupulating it.
+ *
+ * <P>
+ * Logically, the interval patterns are mappings
+ * from (skeleton, the_largest_different_calendar_field)
+ * to (date_interval_pattern).
+ *
+ * <P>
+ * A skeleton
+ * <ol>
+ * <li>
+ * only keeps the field pattern letter and ignores all other parts
+ * in a pattern, such as space, punctuations, and string literals.
+ * <li>
+ * hides the order of fields.
+ * <li>
+ * might hide a field's pattern letter length.
+ *
+ * For those non-digit calendar fields, the pattern letter length is
+ * important, such as MMM, MMMM, and MMMMM; EEE and EEEE,
+ * and the field's pattern letter length is honored.
+ *
+ * For the digit calendar fields, such as M or MM, d or dd, yy or yyyy,
+ * the field pattern length is ignored and the best match, which is defined
+ * in date time patterns, will be returned without honor the field pattern
+ * letter length in skeleton.
+ * </ol>
+ *
+ * <P>
+ * The calendar fields we support for interval formatting are:
+ * year, month, date, day-of-week, am-pm, hour, hour-of-day, and minute.
+ * Those calendar fields can be defined in the following order:
+ * year > month > date > am-pm > hour > minute
+ *
+ * The largest different calendar fields between 2 calendars is the
+ * first different calendar field in above order.
+ *
+ * For example: the largest different calendar fields between "Jan 10, 2007"
+ * and "Feb 20, 2008" is year.
+ *
+ * <P>
+ * There is a set of pre-defined static skeleton strings.
+ * There are pre-defined interval patterns for those pre-defined skeletons
+ * in locales' resource files.
+ * For example, for a skeleton UDAT_YEAR_ABBR_MONTH_DAY, which is "yMMMd",
+ * in en_US, if the largest different calendar field between date1 and date2
+ * is "year", the date interval pattern is "MMM d, yyyy - MMM d, yyyy",
+ * such as "Jan 10, 2007 - Jan 10, 2008".
+ * If the largest different calendar field between date1 and date2 is "month",
+ * the date interval pattern is "MMM d - MMM d, yyyy",
+ * such as "Jan 10 - Feb 10, 2007".
+ * If the largest different calendar field between date1 and date2 is "day",
+ * the date interval pattern is ""MMM d-d, yyyy", such as "Jan 10-20, 2007".
+ *
+ * For date skeleton, the interval patterns when year, or month, or date is
+ * different are defined in resource files.
+ * For time skeleton, the interval patterns when am/pm, or hour, or minute is
+ * different are defined in resource files.
+ *
+ *
+ * <P>
+ * There are 2 dates in interval pattern. For most locales, the first date
+ * in an interval pattern is the earlier date. There might be a locale in which
+ * the first date in an interval pattern is the later date.
+ * We use fallback format for the default order for the locale.
+ * For example, if the fallback format is "{0} - {1}", it means
+ * the first date in the interval pattern for this locale is earlier date.
+ * If the fallback format is "{1} - {0}", it means the first date is the
+ * later date.
+ * For a particular interval pattern, the default order can be overriden
+ * by prefixing "latestFirst:" or "earliestFirst:" to the interval pattern.
+ * For example, if the fallback format is "{0}-{1}",
+ * but for skeleton "yMMMd", the interval pattern when day is different is
+ * "latestFirst:d-d MMM yy", it means by default, the first date in interval
+ * pattern is the earlier date. But for skeleton "yMMMd", when day is different,
+ * the first date in "d-d MMM yy" is the later date.
+ *
+ * <P>
+ * The recommended way to create a DateIntervalFormat object is to pass in
+ * the locale.
+ * By using a Locale parameter, the DateIntervalFormat object is
+ * initialized with the pre-defined interval patterns for a given or
+ * default locale.
+ * <P>
+ * Users can also create DateIntervalFormat object
+ * by supplying their own interval patterns.
+ * It provides flexibility for power users.
+ *
+ * <P>
+ * After a DateIntervalInfo object is created, clients may modify
+ * the interval patterns using setIntervalPattern function as so desired.
+ * Currently, users can only set interval patterns when the following
+ * calendar fields are different: ERA, YEAR, MONTH, DATE, DAY_OF_MONTH,
+ * DAY_OF_WEEK, AM_PM, HOUR, HOUR_OF_DAY, and MINUTE.
+ * Interval patterns when other calendar fields are different is not supported.
+ * <P>
+ * DateIntervalInfo objects are cloneable.
+ * When clients obtain a DateIntervalInfo object,
+ * they can feel free to modify it as necessary.
+ * <P>
+ * DateIntervalInfo are not expected to be subclassed.
+ * Data for a calendar is loaded out of resource bundles.
+ * To ICU 4.0, date interval patterns are only supported in Gregorian calendar.
+ * @stable ICU 4.0
+**/
+
+class U_I18N_API DateIntervalInfo : public UObject {
+public:
+ /**
+ * Default constructor.
+ * It does not initialize any interval patterns except
+ * that it initialize default fall-back pattern as "{0} - {1}",
+ * which can be reset by setFallbackIntervalPattern().
+ * It should be followed by setFallbackIntervalPattern() and
+ * setIntervalPattern(),
+ * and is recommended to be used only for power users who
+ * wants to create their own interval patterns and use them to create
+ * date interval formatter.
+ * @param status output param set to success/failure code on exit
+ * @internal ICU 4.0
+ */
+ DateIntervalInfo(UErrorCode& status);
+
+
+ /**
+ * Construct DateIntervalInfo for the given locale,
+ * @param locale the interval patterns are loaded from the Gregorian
+ * calendar data in this locale.
+ * @param status output param set to success/failure code on exit
+ * @stable ICU 4.0
+ */
+ DateIntervalInfo(const Locale& locale, UErrorCode& status);
+
+
+ /**
+ * Copy constructor.
+ * @stable ICU 4.0
+ */
+ DateIntervalInfo(const DateIntervalInfo&);
+
+ /**
+ * Assignment operator
+ * @stable ICU 4.0
+ */
+ DateIntervalInfo& operator=(const DateIntervalInfo&);
+
+ /**
+ * Clone this object polymorphically.
+ * The caller owns the result and should delete it when done.
+ * @return a copy of the object
+ * @stable ICU 4.0
+ */
+ virtual DateIntervalInfo* clone(void) const;
+
+ /**
+ * Destructor.
+ * It is virtual to be safe, but it is not designed to be subclassed.
+ * @stable ICU 4.0
+ */
+ virtual ~DateIntervalInfo();
+
+
+ /**
+ * Return true if another object is semantically equal to this one.
+ *
+ * @param other the DateIntervalInfo object to be compared with.
+ * @return true if other is semantically equal to this.
+ * @stable ICU 4.0
+ */
+ virtual UBool operator==(const DateIntervalInfo& other) const;
+
+ /**
+ * Return true if another object is semantically unequal to this one.
+ *
+ * @param other the DateIntervalInfo object to be compared with.
+ * @return true if other is semantically unequal to this.
+ * @stable ICU 4.0
+ */
+ UBool operator!=(const DateIntervalInfo& other) const;
+
+
+
+ /**
+ * Provides a way for client to build interval patterns.
+ * User could construct DateIntervalInfo by providing a list of skeletons
+ * and their patterns.
+ * <P>
+ * For example:
+ * <pre>
+ * UErrorCode status = U_ZERO_ERROR;
+ * DateIntervalInfo dIntervalInfo = new DateIntervalInfo();
+ * dIntervalInfo->setFallbackIntervalPattern("{0} ~ {1}");
+ * dIntervalInfo->setIntervalPattern("yMd", UCAL_YEAR, "'from' yyyy-M-d 'to' yyyy-M-d", status);
+ * dIntervalInfo->setIntervalPattern("yMMMd", UCAL_MONTH, "'from' yyyy MMM d 'to' MMM d", status);
+ * dIntervalInfo->setIntervalPattern("yMMMd", UCAL_DAY, "yyyy MMM d-d", status, status);
+ * </pre>
+ *
+ * Restriction:
+ * Currently, users can only set interval patterns when the following
+ * calendar fields are different: ERA, YEAR, MONTH, DATE, DAY_OF_MONTH,
+ * DAY_OF_WEEK, AM_PM, HOUR, HOUR_OF_DAY, and MINUTE.
+ * Interval patterns when other calendar fields are different are
+ * not supported.
+ *
+ * @param skeleton the skeleton on which interval pattern based
+ * @param lrgDiffCalUnit the largest different calendar unit.
+ * @param intervalPattern the interval pattern on the largest different
+ * calendar unit.
+ * For example, if lrgDiffCalUnit is
+ * "year", the interval pattern for en_US when year
+ * is different could be "'from' yyyy 'to' yyyy".
+ * @param status output param set to success/failure code on exit
+ * @stable ICU 4.0
+ */
+ void setIntervalPattern(const UnicodeString& skeleton,
+ UCalendarDateFields lrgDiffCalUnit,
+ const UnicodeString& intervalPattern,
+ UErrorCode& status);
+
+ /**
+ * Get the interval pattern given skeleton and
+ * the largest different calendar field.
+ * @param skeleton the skeleton
+ * @param field the largest different calendar field
+ * @param result output param to receive the pattern
+ * @param status output param set to success/failure code on exit
+ * @return a reference to 'result'
+ * @stable ICU 4.0
+ */
+ UnicodeString& getIntervalPattern(const UnicodeString& skeleton,
+ UCalendarDateFields field,
+ UnicodeString& result,
+ UErrorCode& status) const;
+
+ /**
+ * Get the fallback interval pattern.
+ * @param result output param to receive the pattern
+ * @return a reference to 'result'
+ * @stable ICU 4.0
+ */
+ UnicodeString& getFallbackIntervalPattern(UnicodeString& result) const;
+
+
+ /**
+ * Re-set the fallback interval pattern.
+ *
+ * In construction, default fallback pattern is set as "{0} - {1}".
+ * And constructor taking locale as parameter will set the
+ * fallback pattern as what defined in the locale resource file.
+ *
+ * This method provides a way for user to replace the fallback pattern.
+ *
+ * @param fallbackPattern fall-back interval pattern.
+ * @param status output param set to success/failure code on exit
+ * @stable ICU 4.0
+ */
+ void setFallbackIntervalPattern(const UnicodeString& fallbackPattern,
+ UErrorCode& status);
+
+
+ /** Get default order -- whether the first date in pattern is later date
+ or not.
+ * return default date ordering in interval pattern. TRUE if the first date
+ * in pattern is later date, FALSE otherwise.
+ * @stable ICU 4.0
+ */
+ UBool getDefaultOrder() const;
+
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @stable ICU 4.0
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @stable ICU 4.0
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+
+private:
+ /**
+ * DateIntervalFormat will need access to
+ * getBestSkeleton(), parseSkeleton(), enum IntervalPatternIndex,
+ * and calendarFieldToPatternIndex().
+ *
+ * Instead of making above public,
+ * make DateIntervalFormat a friend of DateIntervalInfo.
+ */
+ friend class DateIntervalFormat;
+
+ friend UBool U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2) ;
+
+ /**
+ * Following is for saving the interval patterns.
+ * We only support interval patterns on
+ * ERA, YEAR, MONTH, DAY, AM_PM, HOUR, and MINUTE
+ */
+ enum IntervalPatternIndex
+ {
+ kIPI_ERA,
+ kIPI_YEAR,
+ kIPI_MONTH,
+ kIPI_DATE,
+ kIPI_AM_PM,
+ kIPI_HOUR,
+ kIPI_MINUTE,
+ kIPI_MAX_INDEX
+ };
+
+ /**
+ * Initialize the DateIntervalInfo from locale
+ * @param locale the given locale.
+ * @param status output param set to success/failure code on exit
+ * @internal ICU 4.0
+ */
+ void initializeData(const Locale& locale, UErrorCode& status);
+
+
+ /* Set Interval pattern.
+ *
+ * It sets interval pattern into the hash map.
+ *
+ * @param skeleton skeleton on which the interval pattern based
+ * @param lrgDiffCalUnit the largest different calendar unit.
+ * @param intervalPattern the interval pattern on the largest different
+ * calendar unit.
+ * @param status output param set to success/failure code on exit
+ * @internal ICU 4.0
+ */
+ void setIntervalPatternInternally(const UnicodeString& skeleton,
+ UCalendarDateFields lrgDiffCalUnit,
+ const UnicodeString& intervalPattern,
+ UErrorCode& status);
+
+
+ /**given an input skeleton, get the best match skeleton
+ * which has pre-defined interval pattern in resource file.
+ * Also return the difference between the input skeleton
+ * and the best match skeleton.
+ *
+ * TODO (xji): set field weight or
+ * isolate the funtionality in DateTimePatternGenerator
+ * @param skeleton input skeleton
+ * @param bestMatchDistanceInfo the difference between input skeleton
+ * and best match skeleton.
+ * 0, if there is exact match for input skeleton
+ * 1, if there is only field width difference between
+ * the best match and the input skeleton
+ * 2, the only field difference is 'v' and 'z'
+ * -1, if there is calendar field difference between
+ * the best match and the input skeleton
+ * @return best match skeleton
+ * @internal ICU 4.0
+ */
+ const UnicodeString* getBestSkeleton(const UnicodeString& skeleton,
+ int8_t& bestMatchDistanceInfo) const;
+
+
+ /**
+ * Parse skeleton, save each field's width.
+ * It is used for looking for best match skeleton,
+ * and adjust pattern field width.
+ * @param skeleton skeleton to be parsed
+ * @param skeletonFieldWidth parsed skeleton field width
+ * @internal ICU 4.0
+ */
+ static void U_EXPORT2 parseSkeleton(const UnicodeString& skeleton,
+ int32_t* skeletonFieldWidth);
+
+
+ /**
+ * Check whether one field width is numeric while the other is string.
+ *
+ * TODO (xji): make it general
+ *
+ * @param fieldWidth one field width
+ * @param anotherFieldWidth another field width
+ * @param patternLetter pattern letter char
+ * @return true if one field width is numeric and the other is string,
+ * false otherwise.
+ * @internal ICU 4.0
+ */
+ static UBool U_EXPORT2 stringNumeric(int32_t fieldWidth,
+ int32_t anotherFieldWidth,
+ char patternLetter);
+
+
+ /**
+ * Convert calendar field to the interval pattern index in
+ * hash table.
+ *
+ * Since we only support the following calendar fields:
+ * ERA, YEAR, MONTH, DATE, DAY_OF_MONTH, DAY_OF_WEEK,
+ * AM_PM, HOUR, HOUR_OF_DAY, and MINUTE,
+ * We reserve only 4 interval patterns for a skeleton.
+ *
+ * @param field calendar field
+ * @param status output param set to success/failure code on exit
+ * @return interval pattern index in hash table
+ * @internal ICU 4.0
+ */
+ static IntervalPatternIndex U_EXPORT2 calendarFieldToIntervalIndex(
+ UCalendarDateFields field,
+ UErrorCode& status);
+
+
+ /**
+ * delete hash table (of type fIntervalPatterns).
+ *
+ * @param hTable hash table to be deleted
+ * @internal ICU 4.0
+ */
+ void deleteHash(Hashtable* hTable);
+
+
+ /**
+ * initialize hash table (of type fIntervalPatterns).
+ *
+ * @param status output param set to success/failure code on exit
+ * @return hash table initialized
+ * @internal ICU 4.0
+ */
+ Hashtable* initHash(UErrorCode& status);
+
+
+
+ /**
+ * copy hash table (of type fIntervalPatterns).
+ *
+ * @param source the source to copy from
+ * @param target the target to copy to
+ * @param status output param set to success/failure code on exit
+ * @internal ICU 4.0
+ */
+ void copyHash(const Hashtable* source, Hashtable* target, UErrorCode& status);
+
+
+ // data members
+ // fallback interval pattern
+ UnicodeString fFallbackIntervalPattern;
+ // default order
+ UBool fFirstDateInPtnIsLaterDate;
+
+ // HashMap<UnicodeString, UnicodeString[kIPI_MAX_INDEX]>
+ // HashMap( skeleton, pattern[largest_different_field] )
+ Hashtable* fIntervalPatterns;
+
+};// end class DateIntervalInfo
+
+
+inline UBool
+DateIntervalInfo::operator!=(const DateIntervalInfo& other) const {
+ return !operator==(other);
+}
+
+
+U_NAMESPACE_END
+
+#endif
+
+#endif
+
Modified: trunk/source/i18n/unicode/dtptngen.h
===================================================================
--- trunk/source/i18n/unicode/dtptngen.h 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/i18n/unicode/dtptngen.h 2009-07-02 19:32:00 UTC (rev 214)
@@ -399,7 +399,7 @@
void addCanonicalItems();
void addICUPatterns(const Locale& locale, UErrorCode& status);
void hackTimes(const UnicodeString& hackPattern, UErrorCode& status);
- void addCLDRData(const Locale& locale);
+ void addCLDRData(const Locale& locale, UErrorCode& status);
UDateTimePatternConflict addPatternWithSkeleton(const UnicodeString& pattern, const UnicodeString * skeletonToUse, UBool override, UnicodeString& conflictingPattern, UErrorCode& status);
void initHashtable(UErrorCode& status);
void setDateTimeFromCalendar(const Locale& locale, UErrorCode& status);
Modified: trunk/source/i18n/unicode/smpdtfmt.h
===================================================================
--- trunk/source/i18n/unicode/smpdtfmt.h 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/i18n/unicode/smpdtfmt.h 2009-07-02 19:32:00 UTC (rev 214)
@@ -947,6 +947,7 @@
/**
* Get the numbering system to be used for a particular field.
*/
+ using DateFormat::getNumberFormat; // Do not hide visibility of base class function
NumberFormat * getNumberFormat(UDateFormatField index) const;
/**
Modified: trunk/source/i18n/unicode/tmunit.h
===================================================================
--- trunk/source/i18n/unicode/tmunit.h 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/i18n/unicode/tmunit.h 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,149 +1,149 @@
-/*
- *******************************************************************************
- * Copyright (C) 2009, Google, International Business Machines Corporation and *
- * others. All Rights Reserved. *
- *******************************************************************************
- */
-
-#ifndef __TMUNIT_H__
-#define __TMUNIT_H__
-
-
-/**
- * \file
- * \brief C++ API: time unit object
- */
-
-
-#include "unicode/measunit.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-U_NAMESPACE_BEGIN
-
-/**
- * Measurement unit for time units.
- * @see TimeUnitAmount
- * @see TimeUnit
- * @draft ICU 4.2
- */
-class U_I18N_API TimeUnit: public MeasureUnit {
-public:
- /**
- * Constants for all the time units we supported.
- * @draft ICU 4.2
- */
- enum UTimeUnitFields {
- UTIMEUNIT_YEAR,
- UTIMEUNIT_MONTH,
- UTIMEUNIT_DAY,
- UTIMEUNIT_WEEK,
- UTIMEUNIT_HOUR,
- UTIMEUNIT_MINUTE,
- UTIMEUNIT_SECOND,
- UTIMEUNIT_FIELD_COUNT
- };
-
- /**
- * Create Instance.
- * @param timeUnitField time unit field based on which the instance
- * is created.
- * @param status input-output error code.
- * If the timeUnitField is invalid,
- * then this will be set to U_ILLEGAL_ARGUMENT_ERROR.
- * @return a TimeUnit instance
- * @draft ICU 4.2
- */
- static TimeUnit* U_EXPORT2 createInstance(UTimeUnitFields timeUnitField,
- UErrorCode& status);
-
-
- /**
- * Override clone.
- * @draft ICU 4.2
- */
- virtual UObject* clone() const;
-
- /**
- * Copy operator.
- * @draft ICU 4.2
- */
- TimeUnit(const TimeUnit& other);
-
- /**
- * Assignment operator.
- * @draft ICU 4.2
- */
- TimeUnit& operator=(const TimeUnit& other);
-
- /**
- * Equality operator.
- * @return true if 2 objects are the same.
- * @draft ICU 4.2
- */
- virtual UBool operator==(const UObject& other) const;
-
- /**
- * Non-Equality operator.
- * @return true if 2 objects are not the same.
- * @draft ICU 4.2
- */
- UBool operator!=(const UObject& other) const;
-
- /**
- * Returns a unique class ID for this object POLYMORPHICALLY.
- * This method implements a simple form of RTTI used by ICU.
- * @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.
- * @draft ICU 4.2
- */
- virtual UClassID getDynamicClassID() const;
-
- /**
- * Returns the class ID for this class. This is used to compare to
- * the return value of getDynamicClassID().
- * @return The class ID for all objects of this class.
- * @draft ICU 4.2
- */
- static UClassID U_EXPORT2 getStaticClassID();
-
-
- /**
- * Get time unit field.
- * @return time unit field.
- * @draft ICU 4.2
- */
- UTimeUnitFields getTimeUnitField() const;
-
- /**
- * Destructor.
- * @draft ICU 4.2
- */
- virtual ~TimeUnit();
-
-private:
- UTimeUnitFields fTimeUnitField;
-
- /**
- * Constructor
- * @internal ICU 4.2
- */
- TimeUnit(UTimeUnitFields timeUnitField);
-
-};
-
-
-inline UBool
-TimeUnit::operator!=(const UObject& other) const {
- return !operator==(other);
-}
-
-
-U_NAMESPACE_END
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
-
-#endif // __TMUNIT_H__
-//eof
-//
+/*
+ *******************************************************************************
+ * Copyright (C) 2009, Google, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+
+#ifndef __TMUNIT_H__
+#define __TMUNIT_H__
+
+
+/**
+ * \file
+ * \brief C++ API: time unit object
+ */
+
+
+#include "unicode/measunit.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Measurement unit for time units.
+ * @see TimeUnitAmount
+ * @see TimeUnit
+ * @draft ICU 4.2
+ */
+class U_I18N_API TimeUnit: public MeasureUnit {
+public:
+ /**
+ * Constants for all the time units we supported.
+ * @draft ICU 4.2
+ */
+ enum UTimeUnitFields {
+ UTIMEUNIT_YEAR,
+ UTIMEUNIT_MONTH,
+ UTIMEUNIT_DAY,
+ UTIMEUNIT_WEEK,
+ UTIMEUNIT_HOUR,
+ UTIMEUNIT_MINUTE,
+ UTIMEUNIT_SECOND,
+ UTIMEUNIT_FIELD_COUNT
+ };
+
+ /**
+ * Create Instance.
+ * @param timeUnitField time unit field based on which the instance
+ * is created.
+ * @param status input-output error code.
+ * If the timeUnitField is invalid,
+ * then this will be set to U_ILLEGAL_ARGUMENT_ERROR.
+ * @return a TimeUnit instance
+ * @draft ICU 4.2
+ */
+ static TimeUnit* U_EXPORT2 createInstance(UTimeUnitFields timeUnitField,
+ UErrorCode& status);
+
+
+ /**
+ * Override clone.
+ * @draft ICU 4.2
+ */
+ virtual UObject* clone() const;
+
+ /**
+ * Copy operator.
+ * @draft ICU 4.2
+ */
+ TimeUnit(const TimeUnit& other);
+
+ /**
+ * Assignment operator.
+ * @draft ICU 4.2
+ */
+ TimeUnit& operator=(const TimeUnit& other);
+
+ /**
+ * Equality operator.
+ * @return true if 2 objects are the same.
+ * @draft ICU 4.2
+ */
+ virtual UBool operator==(const UObject& other) const;
+
+ /**
+ * Non-Equality operator.
+ * @return true if 2 objects are not the same.
+ * @draft ICU 4.2
+ */
+ UBool operator!=(const UObject& other) const;
+
+ /**
+ * Returns a unique class ID for this object POLYMORPHICALLY.
+ * This method implements a simple form of RTTI used by ICU.
+ * @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.
+ * @draft ICU 4.2
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * Returns the class ID for this class. This is used to compare to
+ * the return value of getDynamicClassID().
+ * @return The class ID for all objects of this class.
+ * @draft ICU 4.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+
+ /**
+ * Get time unit field.
+ * @return time unit field.
+ * @draft ICU 4.2
+ */
+ UTimeUnitFields getTimeUnitField() const;
+
+ /**
+ * Destructor.
+ * @draft ICU 4.2
+ */
+ virtual ~TimeUnit();
+
+private:
+ UTimeUnitFields fTimeUnitField;
+
+ /**
+ * Constructor
+ * @internal ICU 4.2
+ */
+ TimeUnit(UTimeUnitFields timeUnitField);
+
+};
+
+
+inline UBool
+TimeUnit::operator!=(const UObject& other) const {
+ return !operator==(other);
+}
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // __TMUNIT_H__
+//eof
+//
Modified: trunk/source/i18n/unicode/tmutamt.h
===================================================================
--- trunk/source/i18n/unicode/tmutamt.h 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/i18n/unicode/tmutamt.h 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,168 +1,168 @@
-/*
- *******************************************************************************
- * Copyright (C) 2009, Google, International Business Machines Corporation and *
- * others. All Rights Reserved. *
- *******************************************************************************
- */
-
-#ifndef __TMUTAMT_H__
-#define __TMUTAMT_H__
-
-
-/**
- * \file
- * \brief C++ API: time unit amount object.
- */
-
-#include "unicode/measure.h"
-#include "unicode/tmunit.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-U_NAMESPACE_BEGIN
-
-
-/**
- * Express a duration as a time unit and number. Patterned after Currency.
- * @see TimeUnitAmount
- * @see TimeUnitFormat
- * @draft ICU 4.2
- */
-class U_I18N_API TimeUnitAmount: public Measure {
-public:
- /**
- * Construct TimeUnitAmount object with the given number and the
- * given time unit.
- * @param number a numeric object; number.isNumeric() must be TRUE
- * @param timeUnitField the time unit field of a time unit
- * @param status the input-output error code.
- * If the number is not numeric or the timeUnitField
- * is not valid,
- * then this will be set to a failing value:
- * U_ILLEGAL_ARGUMENT_ERROR.
- * @draft ICU 4.2
- */
- TimeUnitAmount(const Formattable& number,
- TimeUnit::UTimeUnitFields timeUnitField,
- UErrorCode& status);
-
- /**
- * Construct TimeUnitAmount object with the given numeric amount and the
- * given time unit.
- * @param amount a numeric amount.
- * @param timeUnitField the time unit field on which a time unit amount
- * object will be created.
- * @param status the input-output error code.
- * If the timeUnitField is not valid,
- * then this will be set to a failing value:
- * U_ILLEGAL_ARGUMENT_ERROR.
- * @draft ICU 4.2
- */
- TimeUnitAmount(double amount, TimeUnit::UTimeUnitFields timeUnitField,
- UErrorCode& status);
-
-
- /**
- * Copy constructor
- * @draft ICU 4.2
- */
- TimeUnitAmount(const TimeUnitAmount& other);
-
-
- /**
- * Assignment operator
- * @draft ICU 4.2
- */
- TimeUnitAmount& operator=(const TimeUnitAmount& other);
-
-
- /**
- * Clone.
- * @return a polymorphic clone of this object. The result will have the same class as returned by getDynamicClassID().
- * @draft ICU 4.2
- */
- virtual UObject* clone() const;
-
-
- /**
- * Destructor
- * @draft ICU 4.2
- */
- virtual ~TimeUnitAmount();
-
-
- /**
- * Equality operator.
- * @param other the object to compare to.
- * @return true if this object is equal to the given object.
- * @draft ICU 4.2
- */
- virtual UBool operator==(const UObject& other) const;
-
-
- /**
- * Not-equality operator.
- * @param other the object to compare to.
- * @return true if this object is not equal to the given object.
- * @draft ICU 4.2
- */
- UBool operator!=(const UObject& other) const;
-
-
- /**
- * Return the class ID for this class. This is useful only for comparing to
- * a return value from getDynamicClassID(). For example:
- * <pre>
- * . Base* polymorphic_pointer = createPolymorphicObject();
- * . if (polymorphic_pointer->getDynamicClassID() ==
- * . erived::getStaticClassID()) ...
- * </pre>
- * @return The class ID for all objects of this class.
- * @draft ICU 4.2
- */
- static UClassID U_EXPORT2 getStaticClassID(void);
-
-
- /**
- * 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.
- * @draft ICU 4.2
- */
- virtual UClassID getDynamicClassID(void) const;
-
-
- /**
- * Get the time unit.
- * @return time unit object.
- * @draft ICU 4.2
- */
- const TimeUnit& getTimeUnit() const;
-
- /**
- * Get the time unit field value.
- * @return time unit field value.
- * @draft ICU 4.2
- */
- TimeUnit::UTimeUnitFields getTimeUnitField() const;
-};
-
-
-
-inline UBool
-TimeUnitAmount::operator!=(const UObject& other) const {
- return !operator==(other);
-}
-
-U_NAMESPACE_END
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
-
-#endif // __TMUTAMT_H__
-//eof
-//
+/*
+ *******************************************************************************
+ * Copyright (C) 2009, Google, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+
+#ifndef __TMUTAMT_H__
+#define __TMUTAMT_H__
+
+
+/**
+ * \file
+ * \brief C++ API: time unit amount object.
+ */
+
+#include "unicode/measure.h"
+#include "unicode/tmunit.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+
+/**
+ * Express a duration as a time unit and number. Patterned after Currency.
+ * @see TimeUnitAmount
+ * @see TimeUnitFormat
+ * @draft ICU 4.2
+ */
+class U_I18N_API TimeUnitAmount: public Measure {
+public:
+ /**
+ * Construct TimeUnitAmount object with the given number and the
+ * given time unit.
+ * @param number a numeric object; number.isNumeric() must be TRUE
+ * @param timeUnitField the time unit field of a time unit
+ * @param status the input-output error code.
+ * If the number is not numeric or the timeUnitField
+ * is not valid,
+ * then this will be set to a failing value:
+ * U_ILLEGAL_ARGUMENT_ERROR.
+ * @draft ICU 4.2
+ */
+ TimeUnitAmount(const Formattable& number,
+ TimeUnit::UTimeUnitFields timeUnitField,
+ UErrorCode& status);
+
+ /**
+ * Construct TimeUnitAmount object with the given numeric amount and the
+ * given time unit.
+ * @param amount a numeric amount.
+ * @param timeUnitField the time unit field on which a time unit amount
+ * object will be created.
+ * @param status the input-output error code.
+ * If the timeUnitField is not valid,
+ * then this will be set to a failing value:
+ * U_ILLEGAL_ARGUMENT_ERROR.
+ * @draft ICU 4.2
+ */
+ TimeUnitAmount(double amount, TimeUnit::UTimeUnitFields timeUnitField,
+ UErrorCode& status);
+
+
+ /**
+ * Copy constructor
+ * @draft ICU 4.2
+ */
+ TimeUnitAmount(const TimeUnitAmount& other);
+
+
+ /**
+ * Assignment operator
+ * @draft ICU 4.2
+ */
+ TimeUnitAmount& operator=(const TimeUnitAmount& other);
+
+
+ /**
+ * Clone.
+ * @return a polymorphic clone of this object. The result will have the same class as returned by getDynamicClassID().
+ * @draft ICU 4.2
+ */
+ virtual UObject* clone() const;
+
+
+ /**
+ * Destructor
+ * @draft ICU 4.2
+ */
+ virtual ~TimeUnitAmount();
+
+
+ /**
+ * Equality operator.
+ * @param other the object to compare to.
+ * @return true if this object is equal to the given object.
+ * @draft ICU 4.2
+ */
+ virtual UBool operator==(const UObject& other) const;
+
+
+ /**
+ * Not-equality operator.
+ * @param other the object to compare to.
+ * @return true if this object is not equal to the given object.
+ * @draft ICU 4.2
+ */
+ UBool operator!=(const UObject& other) const;
+
+
+ /**
+ * Return the class ID for this class. This is useful only for comparing to
+ * a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . erived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @draft ICU 4.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+
+ /**
+ * 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.
+ * @draft ICU 4.2
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+
+ /**
+ * Get the time unit.
+ * @return time unit object.
+ * @draft ICU 4.2
+ */
+ const TimeUnit& getTimeUnit() const;
+
+ /**
+ * Get the time unit field value.
+ * @return time unit field value.
+ * @draft ICU 4.2
+ */
+ TimeUnit::UTimeUnitFields getTimeUnitField() const;
+};
+
+
+
+inline UBool
+TimeUnitAmount::operator!=(const UObject& other) const {
+ return !operator==(other);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // __TMUTAMT_H__
+//eof
+//
Modified: trunk/source/i18n/unicode/tmutfmt.h
===================================================================
--- trunk/source/i18n/unicode/tmutfmt.h 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/i18n/unicode/tmutfmt.h 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,281 +1,281 @@
-/*
- *******************************************************************************
- * Copyright (C) 2008, Google, International Business Machines Corporation and *
- * others. All Rights Reserved. *
- *******************************************************************************
- */
-
-#ifndef __TMUTFMT_H__
-#define __TMUTFMT_H__
-
-#include "unicode/utypes.h"
-
-/**
- * \file
- * \brief C++ API: Format and parse duration in single time unit
- */
-
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/unistr.h"
-#include "unicode/tmunit.h"
-#include "unicode/tmutamt.h"
-#include "unicode/measfmt.h"
-#include "unicode/numfmt.h"
-#include "unicode/plurrule.h"
-
-/**
- * @internal ICU 4.2
- */
-
-union UHashTok;
-
-U_NAMESPACE_BEGIN
-
-U_CDECL_BEGIN
-
-/**
- * @internal ICU 4.2
- */
-static UBool U_CALLCONV hashTableValueComparator(UHashTok val1, UHashTok val2) ;
-
-U_CDECL_END
-
-
-class Hashtable;
-
-
-/**
- * Format or parse a TimeUnitAmount, using plural rules for the units where available.
- *
- * <P>
- * Code Sample:
- * <pre>
- * // create time unit amount instance - a combination of Number and time unit
- * UErrorCode status = U_ZERO_ERROR;
- * TimeUnitAmount* source = new TimeUnitAmount(2, TimeUnit::UTIMEUNIT_YEAR, status);
- * // create time unit format instance
- * TimeUnitFormat* format = new TimeUnitFormat(Locale("en"), status);
- * // format a time unit amount
- * UnicodeString formatted;
- * Formattable formattable;
- * if (U_SUCCESS(status)) {
- * formattable.adoptObject(source);
- * formatted = ((Format*)format)->format(formattable, formatted, status);
- * Formattable result;
- * ((Format*)format)->parseObject(formatted, result, status);
- * if (U_SUCCESS(status)) {
- * assert (result == formattable);
- * }
- * }
- * </pre>
- *
- * <P>
- * @see TimeUnitAmount
- * @see TimeUnitFormat
- * @draft ICU 4.2
- */
-class U_I18N_API TimeUnitFormat: public MeasureFormat {
-public:
-
- /**
- * Constants for various styles.
- * There are 2 styles: full name and abbreviated name.
- * For example, for English, the full name for hour duration is "3 hours",
- * and the abbreviated name is "3 hrs".
- * @draft ICU 4.2
- */
- enum EStyle {
- kFull = 0,
- kAbbreviate = 1,
- kTotal = kAbbreviate + 1
- };
-
- /**
- * Create TimeUnitFormat with default locale, and full name style.
- * Use setLocale and/or setFormat to modify.
- * @draft ICU 4.2
- */
- TimeUnitFormat(UErrorCode& status);
-
- /**
- * Create TimeUnitFormat given locale, and full name style.
- * @draft ICU 4.2
- */
- TimeUnitFormat(const Locale& locale, UErrorCode& status);
-
- /**
- * Create TimeUnitFormat given locale and style.
- * @draft ICU 4.2
- */
- TimeUnitFormat(const Locale& locale, EStyle style, UErrorCode& status);
-
- /**
- * Copy constructor.
- * @draft ICU 4.2
- */
- TimeUnitFormat(const TimeUnitFormat&);
-
- /**
- * deconstructor
- * @draft ICU 4.2
- */
- virtual ~TimeUnitFormat();
-
- /**
- * Clone this Format object polymorphically. The caller owns the result and
- * should delete it when done.
- * @return A copy of the object.
- * @draft ICU 4.2
- */
- virtual Format* clone(void) const;
-
- /**
- * Assignment operator
- * @draft ICU 4.2
- */
- TimeUnitFormat& operator=(const TimeUnitFormat& other);
-
-
- /**
- * Return true if the given Format objects are semantically equal. Objects
- * of different subclasses are considered unequal.
- * @param other the object to be compared with.
- * @return true if the given Format objects are semantically equal.
- * @draft ICU 4.2
- */
- virtual UBool operator==(const Format& other) const;
-
- /**
- * Return true if the given Format objects are not semantically equal.
- * Objects of different subclasses are considered unequal.
- * @param other the object to be compared with.
- * @return true if the given Format objects are not semantically equal.
- * @draft ICU 4.2
- */
- UBool operator!=(const Format& other) const;
-
- /**
- * Set the locale used for formatting or parsing.
- * @param locale the locale to be set
- * @param status output param set to success/failure code on exit
- * @draft ICU 4.2
- */
- void setLocale(const Locale& locale, UErrorCode& status);
-
-
- /**
- * Set the number format used for formatting or parsing.
- * @param format the number formatter to be set
- * @param status output param set to success/failure code on exit
- * @draft ICU 4.2
- */
- void setNumberFormat(const NumberFormat& format, UErrorCode& status);
-
- /**
- * Format a TimeUnitAmount.
- * If the formattable object is not a time unit amount object,
- * or the number in time unit amount is not a double type or long type
- * numeric, it returns a failing status: U_ILLEGAL_ARGUMENT_ERROR.
- * @see Format#format(const Formattable&, UnicodeString&, FieldPosition&, UErrorCode&) const
- * @draft ICU 4.2
- */
- virtual UnicodeString& format(const Formattable& obj,
- UnicodeString& toAppendTo,
- FieldPosition& pos,
- UErrorCode& status) const;
-
- /**
- * Parse a TimeUnitAmount.
- * @see Format#parseObject(const UnicodeString&, Formattable&, ParsePosition&) const;
- * @draft ICU 4.2
- */
- virtual void parseObject(const UnicodeString& source,
- Formattable& result,
- ParsePosition& pos) const;
-
- /**
- * Return the class ID for this class. This is useful only for comparing to
- * a return value from getDynamicClassID(). For example:
- * <pre>
- * . Base* polymorphic_pointer = createPolymorphicObject();
- * . if (polymorphic_pointer->getDynamicClassID() ==
- * . erived::getStaticClassID()) ...
- * </pre>
- * @return The class ID for all objects of this class.
- * @draft ICU 4.2
- */
- static UClassID U_EXPORT2 getStaticClassID(void);
-
- /**
- * 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.
- * @draft ICU 4.2
- */
- virtual UClassID getDynamicClassID(void) const;
-
-private:
- NumberFormat* fNumberFormat;
- Locale fLocale;
- Hashtable* fTimeUnitToCountToPatterns[TimeUnit::UTIMEUNIT_FIELD_COUNT];
- PluralRules* fPluralRules;
- EStyle fStyle;
-
- friend UBool U_CALLCONV hashTableValueComparator(UHashTok val1, UHashTok val2);
-
- void create(const Locale& locale, EStyle style, UErrorCode& status);
-
- // it might actually be simpler to make them Decimal Formats later.
- // initialize all private data members
- void setup(UErrorCode& status);
-
- // initialize data member without fill in data for fTimeUnitToCountToPattern
- void initDataMembers(UErrorCode& status);
-
- // initialize fTimeUnitToCountToPatterns from current locale's resource.
- void readFromCurrentLocale(EStyle style, const char* key, UErrorCode& status);
-
- // check completeness of fTimeUnitToCountToPatterns against all time units,
- // and all plural rules, fill in fallback as necessary.
- void checkConsistency(EStyle style, const char* key, UErrorCode& status);
-
- // fill in fTimeUnitToCountToPatterns from locale fall-back chain
- void searchInLocaleChain(EStyle style, const char* key,
- TimeUnit::UTimeUnitFields field, const char*,
- const char*, Hashtable*, UErrorCode&);
-
- // initialize hash table
- Hashtable* initHash(UErrorCode& status);
-
- // delete hash table
- void deleteHash(Hashtable* htable);
-
- // copy hash table
- void copyHash(const Hashtable* source, Hashtable* target, UErrorCode& status);
- // get time unit name, such as "year", from time unit field enum, such as
- // UTIMEUNIT_YEAR.
- static const char* getTimeUnitName(TimeUnit::UTimeUnitFields field, UErrorCode& status);
-};
-
-
-
-inline UBool
-TimeUnitFormat::operator!=(const Format& other) const {
- return !operator==(other);
-}
-
-
-
-U_NAMESPACE_END
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
-
-#endif // __TMUTFMT_H__
-//eof
+/*
+ *******************************************************************************
+ * Copyright (C) 2008, Google, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+
+#ifndef __TMUTFMT_H__
+#define __TMUTFMT_H__
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Format and parse duration in single time unit
+ */
+
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+#include "unicode/tmunit.h"
+#include "unicode/tmutamt.h"
+#include "unicode/measfmt.h"
+#include "unicode/numfmt.h"
+#include "unicode/plurrule.h"
+
+/**
+ * @internal ICU 4.2
+ */
+
+union UHashTok;
+
+U_NAMESPACE_BEGIN
+
+U_CDECL_BEGIN
+
+/**
+ * @internal ICU 4.2
+ */
+static UBool U_CALLCONV hashTableValueComparator(UHashTok val1, UHashTok val2) ;
+
+U_CDECL_END
+
+
+class Hashtable;
+
+
+/**
+ * Format or parse a TimeUnitAmount, using plural rules for the units where available.
+ *
+ * <P>
+ * Code Sample:
+ * <pre>
+ * // create time unit amount instance - a combination of Number and time unit
+ * UErrorCode status = U_ZERO_ERROR;
+ * TimeUnitAmount* source = new TimeUnitAmount(2, TimeUnit::UTIMEUNIT_YEAR, status);
+ * // create time unit format instance
+ * TimeUnitFormat* format = new TimeUnitFormat(Locale("en"), status);
+ * // format a time unit amount
+ * UnicodeString formatted;
+ * Formattable formattable;
+ * if (U_SUCCESS(status)) {
+ * formattable.adoptObject(source);
+ * formatted = ((Format*)format)->format(formattable, formatted, status);
+ * Formattable result;
+ * ((Format*)format)->parseObject(formatted, result, status);
+ * if (U_SUCCESS(status)) {
+ * assert (result == formattable);
+ * }
+ * }
+ * </pre>
+ *
+ * <P>
+ * @see TimeUnitAmount
+ * @see TimeUnitFormat
+ * @draft ICU 4.2
+ */
+class U_I18N_API TimeUnitFormat: public MeasureFormat {
+public:
+
+ /**
+ * Constants for various styles.
+ * There are 2 styles: full name and abbreviated name.
+ * For example, for English, the full name for hour duration is "3 hours",
+ * and the abbreviated name is "3 hrs".
+ * @draft ICU 4.2
+ */
+ enum EStyle {
+ kFull = 0,
+ kAbbreviate = 1,
+ kTotal = kAbbreviate + 1
+ };
+
+ /**
+ * Create TimeUnitFormat with default locale, and full name style.
+ * Use setLocale and/or setFormat to modify.
+ * @draft ICU 4.2
+ */
+ TimeUnitFormat(UErrorCode& status);
+
+ /**
+ * Create TimeUnitFormat given locale, and full name style.
+ * @draft ICU 4.2
+ */
+ TimeUnitFormat(const Locale& locale, UErrorCode& status);
+
+ /**
+ * Create TimeUnitFormat given locale and style.
+ * @draft ICU 4.2
+ */
+ TimeUnitFormat(const Locale& locale, EStyle style, UErrorCode& status);
+
+ /**
+ * Copy constructor.
+ * @draft ICU 4.2
+ */
+ TimeUnitFormat(const TimeUnitFormat&);
+
+ /**
+ * deconstructor
+ * @draft ICU 4.2
+ */
+ virtual ~TimeUnitFormat();
+
+ /**
+ * Clone this Format object polymorphically. The caller owns the result and
+ * should delete it when done.
+ * @return A copy of the object.
+ * @draft ICU 4.2
+ */
+ virtual Format* clone(void) const;
+
+ /**
+ * Assignment operator
+ * @draft ICU 4.2
+ */
+ TimeUnitFormat& operator=(const TimeUnitFormat& other);
+
+
+ /**
+ * Return true if the given Format objects are semantically equal. Objects
+ * of different subclasses are considered unequal.
+ * @param other the object to be compared with.
+ * @return true if the given Format objects are semantically equal.
+ * @draft ICU 4.2
+ */
+ virtual UBool operator==(const Format& other) const;
+
+ /**
+ * Return true if the given Format objects are not semantically equal.
+ * Objects of different subclasses are considered unequal.
+ * @param other the object to be compared with.
+ * @return true if the given Format objects are not semantically equal.
+ * @draft ICU 4.2
+ */
+ UBool operator!=(const Format& other) const;
+
+ /**
+ * Set the locale used for formatting or parsing.
+ * @param locale the locale to be set
+ * @param status output param set to success/failure code on exit
+ * @draft ICU 4.2
+ */
+ void setLocale(const Locale& locale, UErrorCode& status);
+
+
+ /**
+ * Set the number format used for formatting or parsing.
+ * @param format the number formatter to be set
+ * @param status output param set to success/failure code on exit
+ * @draft ICU 4.2
+ */
+ void setNumberFormat(const NumberFormat& format, UErrorCode& status);
+
+ /**
+ * Format a TimeUnitAmount.
+ * If the formattable object is not a time unit amount object,
+ * or the number in time unit amount is not a double type or long type
+ * numeric, it returns a failing status: U_ILLEGAL_ARGUMENT_ERROR.
+ * @see Format#format(const Formattable&, UnicodeString&, FieldPosition&, UErrorCode&) const
+ * @draft ICU 4.2
+ */
+ virtual UnicodeString& format(const Formattable& obj,
+ UnicodeString& toAppendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+
+ /**
+ * Parse a TimeUnitAmount.
+ * @see Format#parseObject(const UnicodeString&, Formattable&, ParsePosition&) const;
+ * @draft ICU 4.2
+ */
+ virtual void parseObject(const UnicodeString& source,
+ Formattable& result,
+ ParsePosition& pos) const;
+
+ /**
+ * Return the class ID for this class. This is useful only for comparing to
+ * a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . erived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @draft ICU 4.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * 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.
+ * @draft ICU 4.2
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+private:
+ NumberFormat* fNumberFormat;
+ Locale fLocale;
+ Hashtable* fTimeUnitToCountToPatterns[TimeUnit::UTIMEUNIT_FIELD_COUNT];
+ PluralRules* fPluralRules;
+ EStyle fStyle;
+
+ friend UBool U_CALLCONV hashTableValueComparator(UHashTok val1, UHashTok val2);
+
+ void create(const Locale& locale, EStyle style, UErrorCode& status);
+
+ // it might actually be simpler to make them Decimal Formats later.
+ // initialize all private data members
+ void setup(UErrorCode& status);
+
+ // initialize data member without fill in data for fTimeUnitToCountToPattern
+ void initDataMembers(UErrorCode& status);
+
+ // initialize fTimeUnitToCountToPatterns from current locale's resource.
+ void readFromCurrentLocale(EStyle style, const char* key, UErrorCode& status);
+
+ // check completeness of fTimeUnitToCountToPatterns against all time units,
+ // and all plural rules, fill in fallback as necessary.
+ void checkConsistency(EStyle style, const char* key, UErrorCode& status);
+
+ // fill in fTimeUnitToCountToPatterns from locale fall-back chain
+ void searchInLocaleChain(EStyle style, const char* key,
+ TimeUnit::UTimeUnitFields field, const char*,
+ const char*, Hashtable*, UErrorCode&);
+
+ // initialize hash table
+ Hashtable* initHash(UErrorCode& status);
+
+ // delete hash table
+ void deleteHash(Hashtable* htable);
+
+ // copy hash table
+ void copyHash(const Hashtable* source, Hashtable* target, UErrorCode& status);
+ // get time unit name, such as "year", from time unit field enum, such as
+ // UTIMEUNIT_YEAR.
+ static const char* getTimeUnitName(TimeUnit::UTimeUnitFields field, UErrorCode& status);
+};
+
+
+
+inline UBool
+TimeUnitFormat::operator!=(const Format& other) const {
+ return !operator==(other);
+}
+
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // __TMUTFMT_H__
+//eof
Modified: trunk/source/i18n/uspoof_impl.cpp
===================================================================
--- trunk/source/i18n/uspoof_impl.cpp 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/i18n/uspoof_impl.cpp 2009-07-02 19:32:00 UTC (rev 214)
@@ -27,7 +27,7 @@
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SpoofImpl)
SpoofImpl::SpoofImpl(SpoofData *data, UErrorCode &status) :
- fMagic(0), fSpoofData(NULL), fAllowedCharsSet(NULL) {
+ fMagic(0), fSpoofData(NULL), fAllowedCharsSet(NULL) , fAllowedLocales(NULL) {
if (U_FAILURE(status)) {
return;
}
Deleted: trunk/source/layout/HindiFeatureTags.h
===================================================================
--- trunk/source/layout/HindiFeatureTags.h 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/layout/HindiFeatureTags.h 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,42 +0,0 @@
-/*
- *
- * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
- *
- */
-
-#ifndef __HINDIFEATURETAGS_H
-#define __HINDIFEATURETAGS_H
-
-/**
- * \file
- * \internal
- */
-
-#include "jni.h"
-#include "LETypes.h"
-#include "OpenTypeTables.h"
-
-U_NAMESPACE_BEGIN
-
-const LETag oopsFeatureTag = 0x6F6F7073; // 'oops'
-
-const LETag nuktFeatureTag = 0x6E756B74; // 'nukt'
-const LETag akhnFeatureTag = 0x616B686E; // 'akhn'
-const LETag rphfFeatureTag = 0x72706866; // 'rphf'
-const LETag blwfFeatureTag = 0x626C7766; // 'blwf'
-const LETag halfFeatureTag = 0x68616C66; // 'half'
-const LETag pstfFeatureTag = 0x70737466; // 'pstf'
-const LETag vatuFeatureTag = 0x76617475; // 'vatu'
-const LETag presFeatureTag = 0x70726573; // 'pres'
-const LETag blwsFeatureTag = 0x626C7773; // 'blws'
-const LETag abvsFeatureTag = 0x61627673; // 'abvs'
-const LETag pstsFeatureTag = 0x70737473; // 'psts'
-const LETag halnFeatureTag = 0x68616C6E; // 'haln'
-
-const LETag blwmFeatureTag = 0x626C776D; // 'blwm'
-const LETag abvmFeatureTag = 0x6162766D; // 'abvm'
-const LETag distFeatureTag = 0x64697374; // 'dist'
-
-U_NAMESPACE_END
-#endif
-
Modified: trunk/source/samples/layout/cgnomelayout.c
===================================================================
--- trunk/source/samples/layout/cgnomelayout.c 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/samples/layout/cgnomelayout.c 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,342 +1,342 @@
-
-/*
- ****************************************************************************** *
- *
- * Copyright (C) 1999-2007, International Business Machines
- * Corporation and others. All Rights Reserved.
- *
- ****************************************************************************** *
- */
-
-#include <gnome.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-
-#include "pflow.h"
-
-#include "gnomeglue.h"
-
-#include "arraymem.h"
-
-struct Context
-{
- long width;
- long height;
- pf_flow *paragraph;
-};
-
-typedef struct Context Context;
-
-static FT_Library engine;
-static gs_guiSupport *guiSupport;
-static fm_fontMap *fontMap;
-static le_font *font;
-
-static GSList *appList = NULL;
-
-GtkWidget *newSample(const gchar *fileName);
-void closeSample(GtkWidget *sample);
-
-static void showabout(GtkWidget *widget, gpointer data)
-{
- GtkWidget *aboutBox;
- const gchar *documentedBy[] = {NULL};
- const gchar *writtenBy[] = {
- "Eric Mader",
- NULL
- };
-
- aboutBox = gnome_about_new("Gnome Layout Sample",
- "0.1",
- "Copyright (C) 1998-2006 By International Business Machines Corporation and others. All Rights Reserved.",
- "A simple demo of the ICU LayoutEngine.",
- writtenBy,
- documentedBy,
- "",
- NULL);
-
- gtk_widget_show(aboutBox);
-}
-
-#if 0
-static void notimpl(GtkObject *object, gpointer data)
-{
- gnome_ok_dialog("Not implemented...");
-}
-#endif
-
-static gchar *prettyTitle(const gchar *path)
-{
- const gchar *name = g_basename(path);
- gchar *title = g_strconcat("Gnome Layout Sample - ", name, NULL);
-
- return title;
-}
-
-static void openOK(GtkObject *object, gpointer data)
-{
- GtkFileSelection *fileselection = GTK_FILE_SELECTION(data);
- GtkWidget *app = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(fileselection), "app"));
- Context *context = (Context *) gtk_object_get_data(GTK_OBJECT(app), "context");
- gchar *fileName = g_strdup(gtk_file_selection_get_filename(fileselection));
- pf_flow *newPara;
-
- gtk_widget_destroy(GTK_WIDGET(fileselection));
-
- newPara = pf_factory(fileName, font, guiSupport);
-
- if (newPara != NULL) {
- gchar *title = prettyTitle(fileName);
- GtkWidget *area = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(app), "area"));
-
- if (context->paragraph != NULL) {
- pf_close(context->paragraph);
- }
-
- context->paragraph = newPara;
- gtk_window_set_title(GTK_WINDOW(app), title);
-
- gtk_widget_hide(area);
- pf_breakLines(context->paragraph, context->width, context->height);
- gtk_widget_show_all(area);
-
- g_free(title);
- }
-
- g_free(fileName);
-}
-
-static void openfile(GtkObject *object, gpointer data)
-{
- GtkWidget *app = GTK_WIDGET(data);
- GtkWidget *fileselection;
- GtkWidget *okButton;
- GtkWidget *cancelButton;
-
- fileselection =
- gtk_file_selection_new("Open File");
-
- gtk_object_set_data(GTK_OBJECT(fileselection), "app", app);
-
- okButton =
- GTK_FILE_SELECTION(fileselection)->ok_button;
-
- cancelButton =
- GTK_FILE_SELECTION(fileselection)->cancel_button;
-
- gtk_signal_connect(GTK_OBJECT(fileselection), "destroy",
- GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
-
- gtk_signal_connect(GTK_OBJECT(okButton), "clicked",
- GTK_SIGNAL_FUNC(openOK), fileselection);
-
- gtk_signal_connect_object(GTK_OBJECT(cancelButton), "clicked",
- GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(fileselection));
-
- gtk_window_set_modal(GTK_WINDOW(fileselection), TRUE);
- gtk_widget_show(fileselection);
- gtk_main();
-}
-
-static void newapp(GtkObject *object, gpointer data)
-{
- GtkWidget *app = newSample("Sample.txt");
-
- gtk_widget_show_all(app);
-}
-
-static void closeapp(GtkWidget *widget, gpointer data)
-{
- GtkWidget *app = GTK_WIDGET(data);
-
- closeSample(app);
-}
-
-static void shutdown(GtkObject *object, gpointer data)
-{
- gtk_main_quit();
-}
-
-GnomeUIInfo fileMenu[] =
-{
- GNOMEUIINFO_MENU_NEW_ITEM((gchar *) "_New Sample",
- (gchar *) "Create a new Gnome Layout Sample",
- newapp, NULL),
-
- GNOMEUIINFO_MENU_OPEN_ITEM(openfile, NULL),
- GNOMEUIINFO_SEPARATOR,
- GNOMEUIINFO_MENU_CLOSE_ITEM(closeapp, NULL),
- GNOMEUIINFO_MENU_EXIT_ITEM(shutdown, NULL),
- GNOMEUIINFO_END
-};
-
-GnomeUIInfo helpMenu[] =
-{
- /* GNOMEUIINFO_HELP("gnomelayout"), */
- GNOMEUIINFO_MENU_ABOUT_ITEM(showabout, NULL),
- GNOMEUIINFO_END
-};
-
-GnomeUIInfo mainMenu[] =
-{
- GNOMEUIINFO_SUBTREE(N_((gchar *) "File"), fileMenu),
- GNOMEUIINFO_SUBTREE(N_((gchar *) "Help"), helpMenu),
- GNOMEUIINFO_END
-};
-
-static gint eventDelete(GtkWidget *widget, GdkEvent *event, gpointer data)
-{
- closeSample(widget);
-
- /* indicate that closeapp already destroyed the window */
- return TRUE;
-}
-
-static gint eventConfigure(GtkWidget *widget, GdkEventConfigure *event, Context *context)
-{
- if (context->paragraph != NULL) {
- context->width = event->width;
- context->height = event->height;
-
- if (context->width > 0 && context->height > 0) {
- pf_breakLines(context->paragraph, context->width, context->height);
- }
- }
-
- return TRUE;
-}
-
-static gint eventExpose(GtkWidget *widget, GdkEvent *event, Context *context)
-{
- if (context->paragraph != NULL) {
- gint maxLines = pf_getLineCount(context->paragraph) - 1;
- gint firstLine = 0, lastLine = context->height / pf_getLineHeight(context->paragraph);
- rs_surface *surface = rs_gnomeRenderingSurfaceOpen(widget);
-
- pf_draw(context->paragraph, surface, firstLine, (maxLines < lastLine)? maxLines : lastLine);
-
- rs_gnomeRenderingSurfaceClose(surface);
- }
-
- return TRUE;
-}
-
-GtkWidget *newSample(const gchar *fileName)
-{
- Context *context = NEW_ARRAY(Context, 1);
- gchar *title;
- GtkWidget *app;
- GtkWidget *area;
- GtkStyle *style;
- int i;
-
- context->width = 600;
- context->height = 400;
- context->paragraph = pf_factory(fileName, font, guiSupport);
-
- title = prettyTitle(fileName);
- app = gnome_app_new("gnomeLayout", title);
-
- gtk_object_set_data(GTK_OBJECT(app), "context", context);
-
- gtk_window_set_default_size(GTK_WINDOW(app), 600 - 24, 400);
-
- gnome_app_create_menus_with_data(GNOME_APP(app), mainMenu, app);
-
- gtk_signal_connect(GTK_OBJECT(app), "delete_event",
- GTK_SIGNAL_FUNC(eventDelete), NULL);
-
- area = gtk_drawing_area_new();
- gtk_object_set_data(GTK_OBJECT(app), "area", area);
-
- style = gtk_style_copy(gtk_widget_get_style(area));
-
- for (i = 0; i < 5; i += 1) {
- style->fg[i] = style->white;
- }
-
- gtk_widget_set_style(area, style);
-
- gnome_app_set_contents(GNOME_APP(app), area);
-
- gtk_signal_connect(GTK_OBJECT(area),
- "expose_event",
- GTK_SIGNAL_FUNC(eventExpose),
- context);
-
- gtk_signal_connect(GTK_OBJECT(area),
- "configure_event",
- GTK_SIGNAL_FUNC(eventConfigure),
- context);
-
- appList = g_slist_prepend(appList, app);
-
- g_free(title);
-
- return app;
-}
-
-void closeSample(GtkWidget *app)
-{
- Context *context = (Context *) gtk_object_get_data(GTK_OBJECT(app), "context");
-
- if (context->paragraph != NULL) {
- pf_close(context->paragraph);
- }
-
- DELETE_ARRAY(context);
-
- appList = g_slist_remove(appList, app);
-
- gtk_widget_destroy(app);
-
- if (appList == NULL) {
- gtk_main_quit();
- }
-}
-
-int main (int argc, char *argv[])
-{
- LEErrorCode fontStatus = LE_NO_ERROR;
- poptContext ptctx;
- GtkWidget *app;
- const char *defaultArgs[] = {"Sample.txt", NULL};
- const char **args;
- int i;
-
- FT_Init_FreeType(&engine);
-
- gnome_init_with_popt_table("gnomelayout", "0.1", argc, argv, NULL, 0, &ptctx);
-
- guiSupport = gs_gnomeGuiSupportOpen();
- fontMap = fm_gnomeFontMapOpen(engine, "FontMap.Gnome", 24, guiSupport, &fontStatus);
- font = le_scriptCompositeFontOpen(fontMap);
-
- if (LE_FAILURE(fontStatus)) {
- FT_Done_FreeType(engine);
- return 1;
- }
-
- args = poptGetArgs(ptctx);
-
- if (args == NULL) {
- args = defaultArgs;
- }
-
- for (i = 0; args[i] != NULL; i += 1) {
- app = newSample(args[i]);
-
- gtk_widget_show_all(app);
- }
-
- poptFreeContext(ptctx);
-
- gtk_main();
-
- le_fontClose(font);
- gs_gnomeGuiSupportClose(guiSupport);
-
- FT_Done_FreeType(engine);
-
- exit(0);
-}
+
+/*
+ ****************************************************************************** *
+ *
+ * Copyright (C) 1999-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *
+ ****************************************************************************** *
+ */
+
+#include <gnome.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#include "pflow.h"
+
+#include "gnomeglue.h"
+
+#include "arraymem.h"
+
+struct Context
+{
+ long width;
+ long height;
+ pf_flow *paragraph;
+};
+
+typedef struct Context Context;
+
+static FT_Library engine;
+static gs_guiSupport *guiSupport;
+static fm_fontMap *fontMap;
+static le_font *font;
+
+static GSList *appList = NULL;
+
+GtkWidget *newSample(const gchar *fileName);
+void closeSample(GtkWidget *sample);
+
+static void showabout(GtkWidget *widget, gpointer data)
+{
+ GtkWidget *aboutBox;
+ const gchar *documentedBy[] = {NULL};
+ const gchar *writtenBy[] = {
+ "Eric Mader",
+ NULL
+ };
+
+ aboutBox = gnome_about_new("Gnome Layout Sample",
+ "0.1",
+ "Copyright (C) 1998-2006 By International Business Machines Corporation and others. All Rights Reserved.",
+ "A simple demo of the ICU LayoutEngine.",
+ writtenBy,
+ documentedBy,
+ "",
+ NULL);
+
+ gtk_widget_show(aboutBox);
+}
+
+#if 0
+static void notimpl(GtkObject *object, gpointer data)
+{
+ gnome_ok_dialog("Not implemented...");
+}
+#endif
+
+static gchar *prettyTitle(const gchar *path)
+{
+ const gchar *name = g_basename(path);
+ gchar *title = g_strconcat("Gnome Layout Sample - ", name, NULL);
+
+ return title;
+}
+
+static void openOK(GtkObject *object, gpointer data)
+{
+ GtkFileSelection *fileselection = GTK_FILE_SELECTION(data);
+ GtkWidget *app = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(fileselection), "app"));
+ Context *context = (Context *) gtk_object_get_data(GTK_OBJECT(app), "context");
+ gchar *fileName = g_strdup(gtk_file_selection_get_filename(fileselection));
+ pf_flow *newPara;
+
+ gtk_widget_destroy(GTK_WIDGET(fileselection));
+
+ newPara = pf_factory(fileName, font, guiSupport);
+
+ if (newPara != NULL) {
+ gchar *title = prettyTitle(fileName);
+ GtkWidget *area = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(app), "area"));
+
+ if (context->paragraph != NULL) {
+ pf_close(context->paragraph);
+ }
+
+ context->paragraph = newPara;
+ gtk_window_set_title(GTK_WINDOW(app), title);
+
+ gtk_widget_hide(area);
+ pf_breakLines(context->paragraph, context->width, context->height);
+ gtk_widget_show_all(area);
+
+ g_free(title);
+ }
+
+ g_free(fileName);
+}
+
+static void openfile(GtkObject *object, gpointer data)
+{
+ GtkWidget *app = GTK_WIDGET(data);
+ GtkWidget *fileselection;
+ GtkWidget *okButton;
+ GtkWidget *cancelButton;
+
+ fileselection =
+ gtk_file_selection_new("Open File");
+
+ gtk_object_set_data(GTK_OBJECT(fileselection), "app", app);
+
+ okButton =
+ GTK_FILE_SELECTION(fileselection)->ok_button;
+
+ cancelButton =
+ GTK_FILE_SELECTION(fileselection)->cancel_button;
+
+ gtk_signal_connect(GTK_OBJECT(fileselection), "destroy",
+ GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
+
+ gtk_signal_connect(GTK_OBJECT(okButton), "clicked",
+ GTK_SIGNAL_FUNC(openOK), fileselection);
+
+ gtk_signal_connect_object(GTK_OBJECT(cancelButton), "clicked",
+ GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(fileselection));
+
+ gtk_window_set_modal(GTK_WINDOW(fileselection), TRUE);
+ gtk_widget_show(fileselection);
+ gtk_main();
+}
+
+static void newapp(GtkObject *object, gpointer data)
+{
+ GtkWidget *app = newSample("Sample.txt");
+
+ gtk_widget_show_all(app);
+}
+
+static void closeapp(GtkWidget *widget, gpointer data)
+{
+ GtkWidget *app = GTK_WIDGET(data);
+
+ closeSample(app);
+}
+
+static void shutdown(GtkObject *object, gpointer data)
+{
+ gtk_main_quit();
+}
+
+GnomeUIInfo fileMenu[] =
+{
+ GNOMEUIINFO_MENU_NEW_ITEM((gchar *) "_New Sample",
+ (gchar *) "Create a new Gnome Layout Sample",
+ newapp, NULL),
+
+ GNOMEUIINFO_MENU_OPEN_ITEM(openfile, NULL),
+ GNOMEUIINFO_SEPARATOR,
+ GNOMEUIINFO_MENU_CLOSE_ITEM(closeapp, NULL),
+ GNOMEUIINFO_MENU_EXIT_ITEM(shutdown, NULL),
+ GNOMEUIINFO_END
+};
+
+GnomeUIInfo helpMenu[] =
+{
+ /* GNOMEUIINFO_HELP("gnomelayout"), */
+ GNOMEUIINFO_MENU_ABOUT_ITEM(showabout, NULL),
+ GNOMEUIINFO_END
+};
+
+GnomeUIInfo mainMenu[] =
+{
+ GNOMEUIINFO_SUBTREE(N_((gchar *) "File"), fileMenu),
+ GNOMEUIINFO_SUBTREE(N_((gchar *) "Help"), helpMenu),
+ GNOMEUIINFO_END
+};
+
+static gint eventDelete(GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+ closeSample(widget);
+
+ /* indicate that closeapp already destroyed the window */
+ return TRUE;
+}
+
+static gint eventConfigure(GtkWidget *widget, GdkEventConfigure *event, Context *context)
+{
+ if (context->paragraph != NULL) {
+ context->width = event->width;
+ context->height = event->height;
+
+ if (context->width > 0 && context->height > 0) {
+ pf_breakLines(context->paragraph, context->width, context->height);
+ }
+ }
+
+ return TRUE;
+}
+
+static gint eventExpose(GtkWidget *widget, GdkEvent *event, Context *context)
+{
+ if (context->paragraph != NULL) {
+ gint maxLines = pf_getLineCount(context->paragraph) - 1;
+ gint firstLine = 0, lastLine = context->height / pf_getLineHeight(context->paragraph);
+ rs_surface *surface = rs_gnomeRenderingSurfaceOpen(widget);
+
+ pf_draw(context->paragraph, surface, firstLine, (maxLines < lastLine)? maxLines : lastLine);
+
+ rs_gnomeRenderingSurfaceClose(surface);
+ }
+
+ return TRUE;
+}
+
+GtkWidget *newSample(const gchar *fileName)
+{
+ Context *context = NEW_ARRAY(Context, 1);
+ gchar *title;
+ GtkWidget *app;
+ GtkWidget *area;
+ GtkStyle *style;
+ int i;
+
+ context->width = 600;
+ context->height = 400;
+ context->paragraph = pf_factory(fileName, font, guiSupport);
+
+ title = prettyTitle(fileName);
+ app = gnome_app_new("gnomeLayout", title);
+
+ gtk_object_set_data(GTK_OBJECT(app), "context", context);
+
+ gtk_window_set_default_size(GTK_WINDOW(app), 600 - 24, 400);
+
+ gnome_app_create_menus_with_data(GNOME_APP(app), mainMenu, app);
+
+ gtk_signal_connect(GTK_OBJECT(app), "delete_event",
+ GTK_SIGNAL_FUNC(eventDelete), NULL);
+
+ area = gtk_drawing_area_new();
+ gtk_object_set_data(GTK_OBJECT(app), "area", area);
+
+ style = gtk_style_copy(gtk_widget_get_style(area));
+
+ for (i = 0; i < 5; i += 1) {
+ style->fg[i] = style->white;
+ }
+
+ gtk_widget_set_style(area, style);
+
+ gnome_app_set_contents(GNOME_APP(app), area);
+
+ gtk_signal_connect(GTK_OBJECT(area),
+ "expose_event",
+ GTK_SIGNAL_FUNC(eventExpose),
+ context);
+
+ gtk_signal_connect(GTK_OBJECT(area),
+ "configure_event",
+ GTK_SIGNAL_FUNC(eventConfigure),
+ context);
+
+ appList = g_slist_prepend(appList, app);
+
+ g_free(title);
+
+ return app;
+}
+
+void closeSample(GtkWidget *app)
+{
+ Context *context = (Context *) gtk_object_get_data(GTK_OBJECT(app), "context");
+
+ if (context->paragraph != NULL) {
+ pf_close(context->paragraph);
+ }
+
+ DELETE_ARRAY(context);
+
+ appList = g_slist_remove(appList, app);
+
+ gtk_widget_destroy(app);
+
+ if (appList == NULL) {
+ gtk_main_quit();
+ }
+}
+
+int main (int argc, char *argv[])
+{
+ LEErrorCode fontStatus = LE_NO_ERROR;
+ poptContext ptctx;
+ GtkWidget *app;
+ const char *defaultArgs[] = {"Sample.txt", NULL};
+ const char **args;
+ int i;
+
+ FT_Init_FreeType(&engine);
+
+ gnome_init_with_popt_table("gnomelayout", "0.1", argc, argv, NULL, 0, &ptctx);
+
+ guiSupport = gs_gnomeGuiSupportOpen();
+ fontMap = fm_gnomeFontMapOpen(engine, "FontMap.Gnome", 24, guiSupport, &fontStatus);
+ font = le_scriptCompositeFontOpen(fontMap);
+
+ if (LE_FAILURE(fontStatus)) {
+ FT_Done_FreeType(engine);
+ return 1;
+ }
+
+ args = poptGetArgs(ptctx);
+
+ if (args == NULL) {
+ args = defaultArgs;
+ }
+
+ for (i = 0; args[i] != NULL; i += 1) {
+ app = newSample(args[i]);
+
+ gtk_widget_show_all(app);
+ }
+
+ poptFreeContext(ptctx);
+
+ gtk_main();
+
+ le_fontClose(font);
+ gs_gnomeGuiSupportClose(guiSupport);
+
+ FT_Done_FreeType(engine);
+
+ exit(0);
+}
Modified: trunk/source/tools/ctestfw/ctest.c
===================================================================
--- trunk/source/tools/ctestfw/ctest.c 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/tools/ctestfw/ctest.c 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,7 +1,7 @@
/*
********************************************************************************
*
-* Copyright (C) 1996-2008, International Business Machines
+* Copyright (C) 1996-2009, International Business Machines
* Corporation and others. All Rights Reserved.
*
********************************************************************************
@@ -482,6 +482,33 @@
}
void T_CTEST_EXPORT2
+log_err_status(UErrorCode status, const char* pattern, ...)
+{
+ va_list ap;
+ va_start(ap, pattern);
+
+ if ((status == U_FILE_ACCESS_ERROR || status == U_MISSING_RESOURCE_ERROR)) {
+ ++DATA_ERROR_COUNT; /* for informational message at the end */
+
+ if (WARN_ON_MISSING_DATA == 0) {
+ /* Fatal error. */
+ if (strchr(pattern, '\n') != NULL) {
+ ++ERROR_COUNT;
+ }
+ vlog_err(NULL, pattern, ap); /* no need for prefix in default case */
+ } else {
+ vlog_info("[DATA] ", pattern, ap);
+ }
+ } else {
+ /* Fatal error. */
+ if(strchr(pattern, '\n') != NULL) {
+ ++ERROR_COUNT;
+ }
+ vlog_err(NULL, pattern, ap); /* no need for prefix in default case */
+ }
+}
+
+void T_CTEST_EXPORT2
log_info(const char* pattern, ...)
{
va_list ap;
@@ -515,7 +542,7 @@
}
vlog_err(NULL, pattern, ap); /* no need for prefix in default case */
} else {
- vlog_info("[Data] ", pattern, ap);
+ vlog_info("[DATA] ", pattern, ap);
}
}
Modified: trunk/source/tools/ctestfw/tstdtmod.cpp
===================================================================
--- trunk/source/tools/ctestfw/tstdtmod.cpp 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/tools/ctestfw/tstdtmod.cpp 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,6 +1,6 @@
/********************************************************************
* COPYRIGHT:
- * Copyright (c) 2002-2008, International Business Machines Corporation and
+ * Copyright (c) 2002-2009, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
@@ -158,7 +158,7 @@
if (testBundle == NULL) {
testBundle = ures_openDirect(icu_data, bundleName, &status);
if (status != U_ZERO_ERROR) {
- fLog.dataerrln(UNICODE_STRING_SIMPLE("[DATA] Could not load test data from resourcebundle: ") + UnicodeString(bundleName, -1, US_INV));
+ fLog.dataerrln(UNICODE_STRING_SIMPLE("Could not load test data from resourcebundle: ") + UnicodeString(bundleName, -1, US_INV) + "\n");
fDataTestValid = FALSE;
}
}
Modified: trunk/source/tools/ctestfw/unicode/ctest.h
===================================================================
--- trunk/source/tools/ctestfw/unicode/ctest.h 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/tools/ctestfw/unicode/ctest.h 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,7 +1,7 @@
/*
********************************************************************************
*
- * Copyright (C) 1996-2008, International Business Machines
+ * Copyright (C) 1996-2009, International Business Machines
* Corporation and others. All Rights Reserved.
*
********************************************************************************
@@ -151,6 +151,8 @@
T_CTEST_API void T_CTEST_EXPORT2
log_err(const char* pattern, ...);
+T_CTEST_API void T_CTEST_EXPORT2
+log_err_status(UErrorCode status, const char* pattern, ...);
/**
* Log an informational message. (printf style)
* @param pattern printf-style format string
Modified: trunk/source/tools/pkgdata/pkgdata.cpp
===================================================================
--- trunk/source/tools/pkgdata/pkgdata.cpp 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/tools/pkgdata/pkgdata.cpp 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,1486 +1,1486 @@
-/******************************************************************************
- * Copyright (C) 2000-2009, International Business Machines
- * Corporation and others. All Rights Reserved.
- *******************************************************************************
- * file name: pkgdata.c
- * encoding: ANSI X3.4 (1968)
- * tab size: 8 (not used)
- * indentation:4
- *
- * created on: 2000may15
- * created by: Steven \u24C7 Loomis
- *
- * This program packages the ICU data into different forms
- * (DLL, common data, etc.)
- */
-
-/*
- * We define _XOPEN_SOURCE so that we can get popen and pclose.
- */
-#if !defined(_XOPEN_SOURCE)
-#if __STDC_VERSION__ >= 199901L
-/* It is invalid to compile an XPG3, XPG4, XPG4v2 or XPG5 application using c99 on Solaris */
-#define _XOPEN_SOURCE 600
-#else
-#define _XOPEN_SOURCE 4
-#endif
-#endif
-
-
-#include "unicode/utypes.h"
-
-#if U_HAVE_POPEN
-#if defined(U_CYGWIN) && defined(__STRICT_ANSI__)
-/* popen/pclose aren't defined in strict ANSI on Cygwin */
-#undef __STRICT_ANSI__
-#endif
-#endif
-
-#include "unicode/putil.h"
-#include "cmemory.h"
-#include "cstring.h"
-#include "filestrm.h"
-#include "toolutil.h"
-#include "unicode/uclean.h"
-#include "unewdata.h"
-#include "uoptions.h"
-#include "putilimp.h"
-#include "package.h"
-#include "pkg_icu.h"
-#include "pkg_genc.h"
-#include "pkg_gencmn.h"
-#include "flagparser.h"
-#include "filetools.h"
-
-
-#if U_HAVE_POPEN
-# include <unistd.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-
-U_CDECL_BEGIN
-#include "pkgtypes.h"
-U_CDECL_END
-
-#ifdef U_WINDOWS
-#ifdef __GNUC__
-#define WINDOWS_WITH_GNUC
-#else
-#define WINDOWS_WITH_MSVC
-#endif
-#endif
-#if !defined(WINDOWS_WITH_MSVC) && !defined(U_LINUX)
-#define BUILD_DATA_WITHOUT_ASSEMBLY
-#endif
-#if defined(WINDOWS_WITH_MSVC) || defined(U_LINUX)
-#define CAN_WRITE_OBJ_CODE
-#endif
-
-/*
- * When building the data library without assembly,
- * some platforms use a single c code file for all of
- * the data to generate the final data library. This can
- * increase the performance of the pkdata tool.
- */
-#if defined(OS400)
-#define USE_SINGLE_CCODE_FILE
-#endif
-
-/* Need to fix the file seperator character when using MinGW. */
-#ifdef WINDOWS_WITH_GNUC
-#define PKGDATA_FILE_SEP_STRING "/"
-#else
-#define PKGDATA_FILE_SEP_STRING U_FILE_SEP_STRING
-#endif
-
-#define LARGE_BUFFER_MAX_SIZE 2048
-#define SMALL_BUFFER_MAX_SIZE 512
-
-static void loadLists(UPKGOptions *o, UErrorCode *status);
-
-static int32_t pkg_executeOptions(UPKGOptions *o);
-
-#ifdef WINDOWS_WITH_MSVC
-static int32_t pkg_createWindowsDLL(const char mode, const char *gencFilePath, UPKGOptions *o);
-#endif
-static int32_t pkg_createSymLinks(const char *targetDir);
-static int32_t pkg_installLibrary(const char *installDir, const char *dir);
-static int32_t pkg_installFileMode(const char *installDir, const char *srcDir, const char *fileListName);
-
-#ifdef BUILD_DATA_WITHOUT_ASSEMBLY
-static int32_t pkg_createWithoutAssemblyCode(UPKGOptions *o, const char *targetDir, const char mode);
-#endif
-
-static int32_t pkg_createWithAssemblyCode(const char *targetDir, const char mode, const char *gencFilePath);
-static int32_t pkg_generateLibraryFile(const char *targetDir, const char mode, const char *objectFile, char *command = NULL);
-static int32_t pkg_archiveLibrary(const char *targetDir, const char *version, UBool reverseExt);
-static void createFileNames(const char *version_major, const char *version, const char *libName, const UBool reverseExt);
-
-static int32_t pkg_getOptionsFromICUConfig(UOption *option);
-
-enum {
- NAME,
- BLDOPT,
- MODE,
- HELP,
- HELP_QUESTION_MARK,
- VERBOSE,
- COPYRIGHT,
- COMMENT,
- DESTDIR,
- REBUILD,
- TEMPDIR,
- INSTALL,
- SOURCEDIR,
- ENTRYPOINT,
- REVISION,
- FORCE_PREFIX,
- LIBNAME,
- QUIET
-};
-
-/* This sets the modes that are available */
-static struct {
- const char *name, *alt_name;
- const char *desc;
-} modes[] = {
- { "files", 0, "Uses raw data files (no effect). Installation copies all files to the target location." },
-#ifdef U_WINDOWS
- { "dll", "library", "Generates one common data file and one shared library, <package>.dll"},
- { "common", "archive", "Generates just the common file, <package>.dat"},
- { "static", "static", "Generates one statically linked library, " LIB_PREFIX "<package>" UDATA_LIB_SUFFIX }
-#else
-#ifdef UDATA_SO_SUFFIX
- { "dll", "library", "Generates one shared library, <package>" UDATA_SO_SUFFIX },
-#endif
- { "common", "archive", "Generates one common data file, <package>.dat" },
- { "static", "static", "Generates one statically linked library, " LIB_PREFIX "<package>" UDATA_LIB_SUFFIX }
-#endif
-};
-
-static UOption options[]={
- /*00*/ UOPTION_DEF( "name", 'p', UOPT_REQUIRES_ARG),
- /*01*/ UOPTION_DEF( "bldopt", 'O', UOPT_REQUIRES_ARG), /* on Win32 it is release or debug */
- /*02*/ UOPTION_DEF( "mode", 'm', UOPT_REQUIRES_ARG),
- /*03*/ UOPTION_HELP_H, /* -h */
- /*04*/ UOPTION_HELP_QUESTION_MARK, /* -? */
- /*05*/ UOPTION_VERBOSE, /* -v */
- /*06*/ UOPTION_COPYRIGHT, /* -c */
- /*07*/ UOPTION_DEF( "comment", 'C', UOPT_REQUIRES_ARG),
- /*08*/ UOPTION_DESTDIR, /* -d */
- /*11*/ UOPTION_DEF( "rebuild", 'F', UOPT_NO_ARG),
- /*12*/ UOPTION_DEF( "tempdir", 'T', UOPT_REQUIRES_ARG),
- /*13*/ UOPTION_DEF( "install", 'I', UOPT_REQUIRES_ARG),
- /*14*/ UOPTION_SOURCEDIR ,
- /*15*/ UOPTION_DEF( "entrypoint", 'e', UOPT_REQUIRES_ARG),
- /*16*/ UOPTION_DEF( "revision", 'r', UOPT_REQUIRES_ARG),
- /*17*/ UOPTION_DEF( "force-prefix", 'f', UOPT_NO_ARG),
- /*18*/ UOPTION_DEF( "libname", 'L', UOPT_REQUIRES_ARG),
- /*19*/ UOPTION_DEF( "quiet", 'q', UOPT_NO_ARG)
-};
-
-enum {
- GENCCODE_ASSEMBLY_TYPE,
- SO_EXT,
- SOBJ_EXT,
- A_EXT,
- LIBPREFIX,
- LIB_EXT_ORDER,
- COMPILER,
- LIBFLAGS,
- GENLIB,
- LDICUDTFLAGS,
- LD_SONAME,
- RPATH_FLAGS,
- BIR_FLAGS,
- AR,
- ARFLAGS,
- RANLIB,
- INSTALL_CMD,
- PKGDATA_FLAGS_SIZE
-};
-static char **pkgDataFlags = NULL;
-
-enum {
- LIB_FILE,
- LIB_FILE_VERSION_MAJOR,
- LIB_FILE_VERSION,
- LIB_FILE_VERSION_TMP,
-#ifdef U_CYGWIN
- LIB_FILE_CYGWIN,
-#endif
- LIB_FILENAMES_SIZE
-};
-static char libFileNames[LIB_FILENAMES_SIZE][256];
-
-static void pkg_checkFlag(UPKGOptions *o);
-
-const char options_help[][320]={
- "Set the data name",
-#ifdef U_MAKE_IS_NMAKE
- "The directory where the ICU is located (e.g. <ICUROOT> which contains the bin directory)",
-#else
- "Specify options for the builder.",
-#endif
- "Specify the mode of building (see below; default: common)",
- "This usage text",
- "This usage text",
- "Make the output verbose",
- "Use the standard ICU copyright",
- "Use a custom comment (instead of the copyright)",
- "Specify the destination directory for files",
- "Force rebuilding of all data",
- "Specify temporary dir (default: output dir)",
- "Install the data (specify target)",
- "Specify a custom source directory",
- "Specify a custom entrypoint name (default: short name)",
- "Specify a version when packaging in DLL or static mode",
- "Add package to all file names if not present",
- "Library name to build (if different than package name)",
- "Quite mode. (e.g. Do not output a readme file for static libraries)"
-};
-
-const char *progname = "PKGDATA";
-
-int
-main(int argc, char* argv[]) {
- int result = 0;
- /* FileStream *out; */
- UPKGOptions o;
- CharList *tail;
- UBool needsHelp = FALSE;
- UErrorCode status = U_ZERO_ERROR;
- /* char tmp[1024]; */
- uint32_t i;
- int32_t n;
-
- U_MAIN_INIT_ARGS(argc, argv);
-
- progname = argv[0];
-
- options[MODE].value = "common";
-
- /* read command line options */
- argc=u_parseArgs(argc, argv, sizeof(options)/sizeof(options[0]), options);
-
- /* error handling, printing usage message */
- /* I've decided to simply print an error and quit. This tool has too
- many options to just display them all of the time. */
-
- if(options[HELP].doesOccur || options[HELP_QUESTION_MARK].doesOccur) {
- needsHelp = TRUE;
- }
- else {
- if(!needsHelp && argc<0) {
- fprintf(stderr,
- "%s: error in command line argument \"%s\"\n",
- progname,
- argv[-argc]);
- fprintf(stderr, "Run '%s --help' for help.\n", progname);
- return 1;
- }
-
-
-#ifndef WINDOWS_WITH_MSVC
- if(!options[BLDOPT].doesOccur) {
- if (pkg_getOptionsFromICUConfig(&options[BLDOPT]) != 0) {
- fprintf(stderr, " required parameter is missing: -O is required \n");
- fprintf(stderr, "Run '%s --help' for help.\n", progname);
- return 1;
- }
- }
-#else
- if(options[BLDOPT].doesOccur) {
- fprintf(stdout, "Warning: You are using the -O option which is not needed for MSVC build on Windows.\n");
- }
-#endif
-
- if(!options[NAME].doesOccur) /* -O we already have - don't report it. */
- {
- fprintf(stderr, " required parameter -p is missing \n");
- fprintf(stderr, "Run '%s --help' for help.\n", progname);
- return 1;
- }
-
- if(argc == 1) {
- fprintf(stderr,
- "No input files specified.\n"
- "Run '%s --help' for help.\n", progname);
- return 1;
- }
- } /* end !needsHelp */
-
- if(argc<0 || needsHelp ) {
- fprintf(stderr,
- "usage: %s [-options] [-] [packageFile] \n"
- "\tProduce packaged ICU data from the given list(s) of files.\n"
- "\t'-' by itself means to read from stdin.\n"
- "\tpackageFile is a text file containing the list of files to package.\n",
- progname);
-
- fprintf(stderr, "\n options:\n");
- for(i=0;i<(sizeof(options)/sizeof(options[0]));i++) {
- fprintf(stderr, "%-5s -%c %s%-10s %s\n",
- (i<1?"[REQ]":""),
- options[i].shortName,
- options[i].longName ? "or --" : " ",
- options[i].longName ? options[i].longName : "",
- options_help[i]);
- }
-
- fprintf(stderr, "modes: (-m option)\n");
- for(i=0;i<(sizeof(modes)/sizeof(modes[0]));i++) {
- fprintf(stderr, " %-9s ", modes[i].name);
- if (modes[i].alt_name) {
- fprintf(stderr, "/ %-9s", modes[i].alt_name);
- } else {
- fprintf(stderr, " ");
- }
- fprintf(stderr, " %s\n", modes[i].desc);
- }
- return 1;
- }
-
- /* OK, fill in the options struct */
- uprv_memset(&o, 0, sizeof(o));
-
- o.mode = options[MODE].value;
- o.version = options[REVISION].doesOccur ? options[REVISION].value : 0;
-
- o.shortName = options[NAME].value;
- {
- int32_t len = (int32_t)uprv_strlen(o.shortName);
- char *csname, *cp;
- const char *sp;
-
- cp = csname = (char *) uprv_malloc((len + 1 + 1) * sizeof(*o.cShortName));
- if (*(sp = o.shortName)) {
- *cp++ = isalpha(*sp) ? * sp : '_';
- for (++sp; *sp; ++sp) {
- *cp++ = isalnum(*sp) ? *sp : '_';
- }
- }
- *cp = 0;
-
- o.cShortName = csname;
- }
-
- if(options[LIBNAME].doesOccur) { /* get libname from shortname, or explicit -L parameter */
- o.libName = options[LIBNAME].value;
- } else {
- o.libName = o.shortName;
- }
-
- if(options[QUIET].doesOccur) {
- o.quiet = TRUE;
- } else {
- o.quiet = FALSE;
- }
-
- o.verbose = options[VERBOSE].doesOccur;
-
-#ifndef WINDOWS_WITH_MSVC /* on UNIX, we'll just include the file... */
- o.options = options[BLDOPT].value;
-#endif
- if(options[COPYRIGHT].doesOccur) {
- o.comment = U_COPYRIGHT_STRING;
- } else if (options[COMMENT].doesOccur) {
- o.comment = options[COMMENT].value;
- }
-
- if( options[DESTDIR].doesOccur ) {
- o.targetDir = options[DESTDIR].value;
- } else {
- o.targetDir = "."; /* cwd */
- }
-
- o.rebuild = options[REBUILD].doesOccur;
-
- if( options[TEMPDIR].doesOccur ) {
- o.tmpDir = options[TEMPDIR].value;
- } else {
- o.tmpDir = o.targetDir;
- }
-
- if( options[INSTALL].doesOccur ) {
- o.install = options[INSTALL].value;
- } else {
- o.install = NULL;
- }
-
- if( options[SOURCEDIR].doesOccur ) {
- o.srcDir = options[SOURCEDIR].value;
- } else {
- o.srcDir = ".";
- }
-
- if( options[ENTRYPOINT].doesOccur ) {
- o.entryName = options[ENTRYPOINT].value;
- } else {
- o.entryName = o.cShortName;
- }
-
- /* OK options are set up. Now the file lists. */
- tail = NULL;
- for( n=1; n<argc; n++) {
- o.fileListFiles = pkg_appendToList(o.fileListFiles, &tail, uprv_strdup(argv[n]));
- }
-
- /* load the files */
- loadLists(&o, &status);
- if( U_FAILURE(status) ) {
- fprintf(stderr, "error loading input file lists: %s\n", u_errorName(status));
- return 2;
- }
-
- result = pkg_executeOptions(&o);
-
- if (pkgDataFlags != NULL) {
- for (n = 0; n < PKGDATA_FLAGS_SIZE; n++) {
- if (pkgDataFlags[n] != NULL) {
- uprv_free(pkgDataFlags[n]);
- }
- }
- uprv_free(pkgDataFlags);
- }
-
- if (o.cShortName != NULL) {
- uprv_free((char *)o.cShortName);
- }
- if (o.fileListFiles != NULL) {
- pkg_deleteList(o.fileListFiles);
- }
- if (o.filePaths != NULL) {
- pkg_deleteList(o.filePaths);
- }
- if (o.files != NULL) {
- pkg_deleteList(o.files);
- }
-
- return result;
-}
-
-#define LN_CMD "ln -s"
-#define RM_CMD "rm -f"
-
-#define MODE_COMMON 'c'
-#define MODE_STATIC 's'
-#define MODE_DLL 'd'
-#define MODE_FILES 'f'
-
-static int32_t pkg_executeOptions(UPKGOptions *o) {
- UErrorCode status = U_ZERO_ERROR;
- int32_t result = 0;
-// char cmd[SMALL_BUFFER_MAX_SIZE] = "";
- const char mode = o->mode[0];
- char targetDir[SMALL_BUFFER_MAX_SIZE] = "";
- char tmpDir[SMALL_BUFFER_MAX_SIZE] = "";
- char datFileName[SMALL_BUFFER_MAX_SIZE] = "";
- char datFileNamePath[LARGE_BUFFER_MAX_SIZE] = "";
- char checkLibFile[LARGE_BUFFER_MAX_SIZE] = "";
-
- /* Initialize pkgdataFlags */
- pkgDataFlags = (char**)uprv_malloc(sizeof(char*) * PKGDATA_FLAGS_SIZE);
- if (pkgDataFlags != NULL) {
- for (int32_t i = 0; i < PKGDATA_FLAGS_SIZE; i++) {
- pkgDataFlags[i] = (char*)uprv_malloc(sizeof(char) * SMALL_BUFFER_MAX_SIZE);
- if (pkgDataFlags[i] != NULL) {
- pkgDataFlags[i][0] = 0;
- } else {
- fprintf(stderr,"Error allocating memory for pkgDataFlags.\n");
- return -1;
- }
- }
- } else {
- fprintf(stderr,"Error allocating memory for pkgDataFlags.\n");
- return -1;
- }
-#ifndef WINDOWS_WITH_MSVC
- /* Read in options file. */
- parseFlagsFile(o->options, pkgDataFlags, SMALL_BUFFER_MAX_SIZE, (int32_t)PKGDATA_FLAGS_SIZE, &status);
- if (U_FAILURE(status)) {
- fprintf(stderr,"Unable to open or read \"%s\" option file.\n", o->options);
- return -1;
- }
-#endif
- if (mode == MODE_FILES) {
- /* Copy the raw data to the installation directory. */
- if (o->install != NULL) {
- uprv_strcpy(targetDir, o->install);
- if (o->shortName != NULL) {
- uprv_strcat(targetDir, PKGDATA_FILE_SEP_STRING);
- uprv_strcat(targetDir, o->shortName);
- }
- result = pkg_installFileMode(targetDir, o->srcDir, o->fileListFiles->str);
- }
- return result;
- } else /* if (mode == MODE_COMMON || mode == MODE_STATIC || mode == MODE_DLL) */ {
- uprv_strcpy(targetDir, o->targetDir);
- uprv_strcat(targetDir, PKGDATA_FILE_SEP_STRING);
-
- uprv_strcpy(tmpDir, o->tmpDir);
- uprv_strcat(tmpDir, PKGDATA_FILE_SEP_STRING);
-
- uprv_strcpy(datFileNamePath, tmpDir);
-
- uprv_strcpy(datFileName, o->shortName);
- uprv_strcat(datFileName, UDATA_CMN_SUFFIX);
-
- uprv_strcat(datFileNamePath, datFileName);
-
- result = writePackageDatFile(datFileNamePath, o->comment, o->srcDir, o->fileListFiles->str, NULL, U_IS_BIG_ENDIAN ? 'b' : 'l');
- if (result != 0) {
- fprintf(stderr,"Error writing package dat file.\n");
- return result;
- }
-
- if (mode == MODE_COMMON) {
- char targetFileNamePath[LARGE_BUFFER_MAX_SIZE] = "";
-
- uprv_strcpy(targetFileNamePath, targetDir);
- uprv_strcat(targetFileNamePath, datFileName);
-
- if (T_FileStream_file_exists(targetFileNamePath)) {
- if ((result = remove(targetFileNamePath)) != 0) {
- fprintf(stderr, "Unable to remove old dat file: %s\n", targetFileNamePath);
- return result;
- }
- }
-
- /* Move the dat file created to the target directory. */
- result = rename(datFileNamePath, targetFileNamePath);
- if (result != 0) {
- fprintf(stderr, "Unable to move dat file (%s) to target location (%s).\n", datFileNamePath, targetFileNamePath);
- }
-
- return result;
- } else /* if (mode[0] == MODE_STATIC || mode[0] == MODE_DLL) */ {
- char gencFilePath[SMALL_BUFFER_MAX_SIZE] = "";
- char version_major[10] = "";
- UBool reverseExt = FALSE;
-
-#ifndef WINDOWS_WITH_MSVC
- /* Get the version major number. */
- if (o->version != NULL) {
- for (uint32_t i = 0;i < sizeof(version_major);i++) {
- if (o->version[i] == '.') {
- version_major[i] = 0;
- break;
- }
- version_major[i] = o->version[i];
- }
- }
-
-#ifndef OS400
- /* Certain platforms have different library extension ordering. (e.g. libicudata.##.so vs libicudata.so.##)
- * reverseExt is FALSE if the suffix should be the version number.
- */
- if (pkgDataFlags[LIB_EXT_ORDER][uprv_strlen(pkgDataFlags[LIB_EXT_ORDER])-1] == pkgDataFlags[SO_EXT][uprv_strlen(pkgDataFlags[SO_EXT])-1]) {
- reverseExt = TRUE;
- }
-#endif
- /* Using the base libName and version number, generate the library file names. */
- createFileNames(version_major, o->version, o->libName, reverseExt);
-
- if (o->version != 0 && o->rebuild == FALSE) {
- /* Check to see if a previous built data library file exists and check if it is the latest. */
- sprintf(checkLibFile, "%s%s", targetDir, libFileNames[LIB_FILE_VERSION_TMP]);
- if (T_FileStream_file_exists(checkLibFile)) {
- if (isFileModTimeLater(checkLibFile, o->srcDir, TRUE) && isFileModTimeLater(checkLibFile, o->options)) {
- if (o->install != NULL) {
- uprv_strcpy(libFileNames[LIB_FILE_VERSION], libFileNames[LIB_FILE_VERSION_TMP]);
- result = pkg_installLibrary(o->install, targetDir);
- }
- return result;
- }
- }
- }
-
- pkg_checkFlag(o);
-#endif
-
- if (pkgDataFlags[GENCCODE_ASSEMBLY_TYPE][0] != 0) {
- const char* genccodeAssembly = pkgDataFlags[GENCCODE_ASSEMBLY_TYPE];
-
- /* Offset genccodeAssembly by 3 because "-a " */
- if (checkAssemblyHeaderName(genccodeAssembly+3)) {
- writeAssemblyCode(datFileNamePath, o->tmpDir, o->entryName, NULL, gencFilePath);
-
- result = pkg_createWithAssemblyCode(targetDir, mode, gencFilePath);
- if (result != 0) {
- fprintf(stderr, "Error generating assembly code for data.\n");
- return result;
- } else if (mode == MODE_STATIC) {
- return result;
- }
- } else {
- fprintf(stderr,"Assembly type \"%s\" is unknown.\n", genccodeAssembly);
- return -1;
- }
- } else {
-#ifdef CAN_WRITE_OBJ_CODE
- writeObjectCode(datFileNamePath, o->tmpDir, o->entryName, NULL, NULL, gencFilePath);
-#ifdef U_LINUX
- result = pkg_generateLibraryFile(targetDir, mode, gencFilePath);
-#elif defined(WINDOWS_WITH_MSVC)
- return pkg_createWindowsDLL(mode, gencFilePath, o);
-#endif
-#elif defined(BUILD_DATA_WITHOUT_ASSEMBLY)
- result = pkg_createWithoutAssemblyCode(o, targetDir, mode);
-#endif
- if (result != 0) {
- fprintf(stderr, "Error generating package data.\n");
- return result;
- }
- }
-#ifndef U_WINDOWS
- /* Certain platforms uses archive library. (e.g. AIX) */
- result = pkg_archiveLibrary(targetDir, o->version, reverseExt);
- if (result != 0) {
- fprintf(stderr, "Error creating data archive library file.\n");
- return result;
- }
-#ifndef OS400
- /* Create symbolic links for the final library file. */
- result = pkg_createSymLinks(targetDir);
- if (result != 0) {
- fprintf(stderr, "Error creating symbolic links of the data library file.\n");
- return result;
- }
-#endif
- /* Install the libraries if option was set. */
- if (o->install != NULL) {
- result = pkg_installLibrary(o->install, targetDir);
- if (result != 0) {
- fprintf(stderr, "Error installing the data library.\n");
- return result;
- }
- }
-#endif
- }
- }
- return result;
-}
-/*
- * Given the base libName and version numbers, generate the libary file names and store it in libFileNames.
- * Depending on the configuration, the library name may either end with version number or shared object suffix.
- */
-static void createFileNames(const char *version_major, const char *version, const char *libName, UBool reverseExt) {
- sprintf(libFileNames[LIB_FILE], "%s%s",
- pkgDataFlags[LIBPREFIX],
- libName);
- if (version != NULL) {
-#ifdef U_CYGWIN
- sprintf(libFileNames[LIB_FILE_CYGWIN], "cyg%s%s.%s",
- libName,
- version_major,
- pkgDataFlags[SO_EXT]);
-
- sprintf(pkgDataFlags[SO_EXT], "%s.%s",
- pkgDataFlags[SO_EXT],
- pkgDataFlags[A_EXT]);
-#elif defined(OS400)
- sprintf(libFileNames[LIB_FILE_VERSION_TMP], "%s.%s",
- libFileNames[LIB_FILE],
- pkgDataFlags[SOBJ_EXT]);
-#else
- sprintf(libFileNames[LIB_FILE_VERSION_TMP], "%s%s%s.%s",
- libFileNames[LIB_FILE],
- pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "",
- reverseExt ? version : pkgDataFlags[SOBJ_EXT],
- reverseExt ? pkgDataFlags[SOBJ_EXT] : version);
-#endif
- sprintf(libFileNames[LIB_FILE_VERSION_MAJOR], "%s%s%s.%s",
- libFileNames[LIB_FILE],
- pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "",
- reverseExt ? version_major : pkgDataFlags[SO_EXT],
- reverseExt ? pkgDataFlags[SO_EXT] : version_major);
-
- libFileNames[LIB_FILE_VERSION][0] = 0;
-
-#ifdef U_CYGWIN
- /* Cygwin only deals with the version major number. */
- uprv_strcpy(libFileNames[LIB_FILE_VERSION_TMP], libFileNames[LIB_FILE_VERSION_MAJOR]);
-#endif
- }
-}
-
-/* Create the symbolic links for the final library file. */
-static int32_t pkg_createSymLinks(const char *targetDir) {
- int32_t result = 0;
- char cmd[LARGE_BUFFER_MAX_SIZE];
-
-#ifndef U_CYGWIN
- /* No symbolic link to make. */
- if (uprv_strlen(libFileNames[LIB_FILE_VERSION]) == 0 || uprv_strlen(libFileNames[LIB_FILE_VERSION_MAJOR]) == 0) {
- return result;
- }
-
- sprintf(cmd, "cd %s && %s %s && %s %s %s",
- targetDir,
- RM_CMD,
- libFileNames[LIB_FILE_VERSION_MAJOR],
- LN_CMD,
- libFileNames[LIB_FILE_VERSION],
- libFileNames[LIB_FILE_VERSION_MAJOR]);
- result = system(cmd);
- if (result != 0) {
- return result;
- }
-#endif
- sprintf(cmd, "cd %s && %s %s.%s && %s %s %s.%s",
- targetDir,
- RM_CMD,
- libFileNames[LIB_FILE], pkgDataFlags[SO_EXT],
- LN_CMD,
- libFileNames[LIB_FILE_VERSION],
- libFileNames[LIB_FILE], pkgDataFlags[SO_EXT]);
-
- result = system(cmd);
-
- return result;
-}
-
-static int32_t pkg_installLibrary(const char *installDir, const char *targetDir) {
- int32_t result = 0;
- char cmd[SMALL_BUFFER_MAX_SIZE];
-
- sprintf(cmd, "cd %s && %s %s %s%s%s",
- targetDir,
- pkgDataFlags[INSTALL_CMD],
- libFileNames[LIB_FILE_VERSION],
- installDir, PKGDATA_FILE_SEP_STRING, libFileNames[LIB_FILE_VERSION]
- );
-
- result = system(cmd);
-
- if (result != 0) {
- return result;
- }
-
- return pkg_createSymLinks(installDir);
-}
-
-#ifdef U_WINDOWS_MSVC
-/* Copy commands for installing the raw data files on Windows. */
-#define WIN_INSTALL_CMD "xcopy"
-#define WIN_INSTALL_CMD_FLAGS "/E /Y /K"
-#endif
-static int32_t pkg_installFileMode(const char *installDir, const char *srcDir, const char *fileListName) {
- int32_t result = 0;
- char cmd[SMALL_BUFFER_MAX_SIZE] = "";
-
- if (!T_FileStream_file_exists(installDir)) {
- UErrorCode status = U_ZERO_ERROR;
-
- uprv_mkdir(installDir, &status);
- if (U_FAILURE(status)) {
- fprintf(stderr, "Error creating installation directory: %s\n", installDir);
- return -1;
- }
- }
-#ifndef U_WINDOWS_WITH_MSVC
- char buffer[SMALL_BUFFER_MAX_SIZE] = "";
-
- FileStream *f = T_FileStream_open(fileListName, "r");
- if (f != NULL) {
- for(;;) {
- if (T_FileStream_readLine(f, buffer, SMALL_BUFFER_MAX_SIZE) != NULL) {
- /* Remove new line character. */
- buffer[uprv_strlen(buffer)-1] = 0;
-
- sprintf(cmd, "%s %s%s%s %s%s%s",
- pkgDataFlags[INSTALL_CMD],
- srcDir, PKGDATA_FILE_SEP_STRING, buffer,
- installDir, PKGDATA_FILE_SEP_STRING, buffer);
-
- result = system(cmd);
- if (result != 0) {
- fprintf(stderr, "Failed to install data file with command: %s\n", cmd);
- break;
- }
- } else {
- if (!T_FileStream_eof(f)) {
- fprintf(stderr, "Failed to read line from file: %s\n", fileListName);
- result = -1;
- }
- break;
- }
- }
- T_FileStream_close(f);
- } else {
- result = -1;
- fprintf(stderr, "Unable to open list file: %s\n", fileListName);
- }
-#else
- sprintf(cmd, "%s %s %s %s", WIN_INSTALL_CMD, srcDir, installDir, WIN_INSTALL_CMD_FLAGS);
- result = system(cmd);
- if (result != 0) {
- fprintf(stderr, "Failed to install data file with command: %s\n", cmd);
- }
-#endif
-
- return result;
-}
-
-/* Archiving of the library file may be needed depending on the platform and options given.
- * If archiving is not needed, copy over the library file name.
- */
-static int32_t pkg_archiveLibrary(const char *targetDir, const char *version, UBool reverseExt) {
- int32_t result = 0;
- char cmd[LARGE_BUFFER_MAX_SIZE];
-
- /* If the shard object suffix and the final object suffix is different and the final object suffix and the
- * archive file suffix is the same, then the final library needs to be archived.
- */
- if (uprv_strcmp(pkgDataFlags[SOBJ_EXT], pkgDataFlags[SO_EXT]) != 0 && uprv_strcmp(pkgDataFlags[A_EXT], pkgDataFlags[SO_EXT]) == 0) {
- sprintf(libFileNames[LIB_FILE_VERSION], "%s%s%s.%s",
- libFileNames[LIB_FILE],
- pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "",
- reverseExt ? version : pkgDataFlags[SO_EXT],
- reverseExt ? pkgDataFlags[SO_EXT] : version);
-
- sprintf(cmd, "%s %s %s%s %s%s",
- pkgDataFlags[AR],
- pkgDataFlags[ARFLAGS],
- targetDir,
- libFileNames[LIB_FILE_VERSION],
- targetDir,
- libFileNames[LIB_FILE_VERSION_TMP]);
-
- result = system(cmd);
- if (result != 0) {
- return result;
- }
-
- /* Remove unneeded library file. */
- sprintf(cmd, "%s %s%s",
- RM_CMD,
- targetDir,
- libFileNames[LIB_FILE_VERSION_TMP]);
-
- result = system(cmd);
- if (result != 0) {
- return result;
- }
-
- } else {
- uprv_strcpy(libFileNames[LIB_FILE_VERSION], libFileNames[LIB_FILE_VERSION_TMP]);
- }
-
- return result;
-}
-
-/*
- * Using the compiler information from the configuration file set by -O option, generate the library file.
- * command may be given to allow for a larger buffer for cmd.
- */
-static int32_t pkg_generateLibraryFile(const char *targetDir, const char mode, const char *objectFile, char *command) {
- int32_t result = 0;
- char *cmd = NULL;
- UBool freeCmd = FALSE;
-
- /* This is necessary because if packaging is done without assembly code, objectFile might be extremely large
- * containing many object files and so the calling function should supply a command buffer that is large
- * enough to handle this. Otherwise, use the default size.
- */
- if (command != NULL) {
- cmd = command;
- } else {
- if ((cmd = (char *)uprv_malloc(sizeof(char) * LARGE_BUFFER_MAX_SIZE)) == NULL) {
- fprintf(stderr, "Unable to allocate memory for command.\n");
- return -1;
- }
- freeCmd = TRUE;
- }
-
- if (mode == MODE_STATIC) {
-#ifdef OS400
- sprintf(cmd, "QSH CMD('%s %s %s%s.%s %s')",
-#else
- sprintf(cmd, "%s %s %s%s.%s %s",
-#endif
- pkgDataFlags[AR],
- pkgDataFlags[ARFLAGS],
- targetDir,
- libFileNames[LIB_FILE],
- pkgDataFlags[A_EXT],
- objectFile);
-
- result = system(cmd);
- } else /* if (mode == MODE_DLL) */ {
-#ifdef U_CYGWIN
- sprintf(cmd, "%s%s%s %s -o %s%s %s %s%s %s %s",
- pkgDataFlags[GENLIB],
- targetDir,
- libFileNames[LIB_FILE_VERSION_TMP],
- pkgDataFlags[LDICUDTFLAGS],
- targetDir, libFileNames[LIB_FILE_CYGWIN],
-#else
-#ifdef OS400
- sprintf(cmd, "QSH CMD('%s %s -o %s%s %s %s%s %s %s')",
-#else
- sprintf(cmd, "%s %s -o %s%s %s %s%s %s %s",
-#endif
- pkgDataFlags[GENLIB],
- pkgDataFlags[LDICUDTFLAGS],
- targetDir,
- libFileNames[LIB_FILE_VERSION_TMP],
-#endif
- objectFile,
- pkgDataFlags[LD_SONAME],
- pkgDataFlags[LD_SONAME][0] == 0 ? "" : libFileNames[LIB_FILE_VERSION_MAJOR],
- pkgDataFlags[RPATH_FLAGS],
- pkgDataFlags[BIR_FLAGS]);
-
- /* Generate the library file. */
- result = system(cmd);
- }
-
- if (freeCmd) {
- uprv_free(cmd);
- }
-
- return result;
-}
-
-static int32_t pkg_createWithAssemblyCode(const char *targetDir, const char mode, const char *gencFilePath) {
- char tempObjectFile[SMALL_BUFFER_MAX_SIZE] = "";
- char cmd[LARGE_BUFFER_MAX_SIZE] = "";
- int32_t result = 0;
-
- /* Remove the ending .s and replace it with .o for the new object file. */
- uprv_strcpy(tempObjectFile, gencFilePath);
- tempObjectFile[uprv_strlen(tempObjectFile)-1] = 'o';
-
- /* Generate the object file. */
- sprintf(cmd, "%s %s -o %s %s",
- pkgDataFlags[COMPILER],
- pkgDataFlags[LIBFLAGS],
- tempObjectFile,
- gencFilePath);
-
- result = system(cmd);
- if (result != 0) {
- return result;
- }
-
- return pkg_generateLibraryFile(targetDir, mode, tempObjectFile);
-}
-
-#ifdef BUILD_DATA_WITHOUT_ASSEMBLY
-/*
- * Generation of the data library without assembly code needs to compile each data file
- * individually and then link it all together.
- */
-enum {
- DATA_PREFIX_BRKITR,
- DATA_PREFIX_COLL,
- DATA_PREFIX_RBNF,
- DATA_PREFIX_TRANSLIT,
- DATA_PREFIX_LENGTH
-};
-const static char DATA_PREFIX[DATA_PREFIX_LENGTH][10] = {
- "brkitr",
- "coll",
- "rbnf",
- "translit"
-};
-static int32_t pkg_createWithoutAssemblyCode(UPKGOptions *o, const char *targetDir, const char mode) {
- int32_t result = 0;
- CharList *list = o->filePaths;
- CharList *listNames = o->files;
- int32_t listSize = pkg_countCharList(list);
- char *buffer;
- char *cmd;
- char gencmnFile[SMALL_BUFFER_MAX_SIZE] = "";
- char tempObjectFile[SMALL_BUFFER_MAX_SIZE] = "";
-#ifdef USE_SINGLE_CCODE_FILE
- char icudtAll[SMALL_BUFFER_MAX_SIZE] = "";
-
- sprintf(icudtAll, "%s%s%sall.c",
- o->tmpDir,
- PKGDATA_FILE_SEP_STRING,
- libFileNames[LIB_FILE]);
-#endif
-
- if (list == NULL || listNames == NULL) {
- /* list and listNames should never be NULL since we are looping through the CharList with
- * the given size.
- */
- return -1;
- }
-
- if ((cmd = (char *)uprv_malloc((listSize + 2) * SMALL_BUFFER_MAX_SIZE)) == NULL) {
- fprintf(stderr, "Unable to allocate memory for cmd.\n");
- return -1;
- } else if ((buffer = (char *)uprv_malloc((listSize + 1) * SMALL_BUFFER_MAX_SIZE)) == NULL) {
- fprintf(stderr, "Unable to allocate memory for buffer.\n");
- uprv_free(cmd);
- return -1;
- }
-
- for (int32_t i = 0; i < (listSize + 1); i++) {
- const char *file ;
- const char *name;
-
- if (i == 0) {
- /* The first iteration calls the gencmn function and initailizes the buffer. */
- createCommonDataFile(o->tmpDir, o->shortName, o->entryName, NULL, o->srcDir, o->comment, o->fileListFiles->str, 0, TRUE, o->verbose, gencmnFile);
- buffer[0] = 0;
-#ifdef USE_SINGLE_CCODE_FILE
- uprv_strcpy(tempObjectFile, gencmnFile);
- tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
-
-#ifdef OS400
- sprintf(cmd, "QSH CMD('%s %s -o %s %s')",
-#else
- sprintf(cmd, "%s %s -o %s %s"
-#endif
- pkgDataFlags[COMPILER],
- pkgDataFlags[LIBFLAGS],
- tempObjectFile,
- gencmnFile);
-
- result = system(cmd);
- if (result != 0) {
- break;
- }
-
- sprintf(buffer, "%s",tempObjectFile);
-#endif
- } else {
- char newName[SMALL_BUFFER_MAX_SIZE];
- char dataName[SMALL_BUFFER_MAX_SIZE];
- const char *pSubstring;
- file = list->str;
- name = listNames->str;
-
- newName[0] = dataName[0] = 0;
- for (int32_t n = 0; n < DATA_PREFIX_LENGTH; n++) {
- /* If the name contains a prefix, alter the new name accordingly. */
- pSubstring = uprv_strstr(name, DATA_PREFIX[n]);
- if (pSubstring != NULL) {
- char newNameTmp[SMALL_BUFFER_MAX_SIZE] = "";
- const char *p = name + uprv_strlen(DATA_PREFIX[n]) + 1;
- for (int32_t i = 0;;i++) {
- if (p[i] == '.') {
- newNameTmp[i] = '_';
- continue;
- }
- newNameTmp[i] = p[i];
- if (p[i] == 0) {
- break;
- }
- }
- sprintf(newName, "%s_%s",
- DATA_PREFIX[n],
- newNameTmp);
- sprintf(dataName, "%s_%s",
- o->shortName,
- DATA_PREFIX[n]);
- }
- if (newName[0] != 0) {
- break;
- }
- }
-
- writeCCode(file, o->tmpDir, dataName[0] != 0 ? dataName : o->shortName, newName[0] != 0 ? newName : NULL, gencmnFile);
-#ifdef USE_SINGLE_CCODE_FILE
-#ifdef OS400
- sprintf(cmd, "QSH CMD('cat %s >> %s')", gencmnFile, icudtAll);
-#else
- sprintf(cmd, "cat %s >> %s", gencmnFile, icudtAll);
-#endif
-
- result = system(cmd);
- if (result != 0) {
- break;
- }
-#endif
- }
-
-#ifndef USE_SINGLE_CCODE_FILE
- uprv_strcpy(tempObjectFile, gencmnFile);
- tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
-
- sprintf(cmd, "%s %s -o %s %s",
- pkgDataFlags[COMPILER],
- pkgDataFlags[LIBFLAGS],
- tempObjectFile,
- gencmnFile);
- result = system(cmd);
- if (result != 0) {
- break;
- }
-
- sprintf(buffer, "%s %s",
- buffer,
- tempObjectFile);
-#endif
-
- if (i > 0) {
- list = list->next;
- listNames = listNames->next;
- }
- }
-
-#ifdef USE_SINGLE_CCODE_FILE
- uprv_strcpy(tempObjectFile, icudtAll);
- tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
-#ifdef OS400
- sprintf(cmd, "QSH CMD('%s %s -o %s %s')",
-#else
- sprintf(cmd, "%s %s -o %s %s",
-#endif
- pkgDataFlags[COMPILER],
- pkgDataFlags[LIBFLAGS],
- tempObjectFile,
- icudtAll);
-
- result = system(cmd);
- if (result == 0) {
- sprintf(buffer, "%s %s",
- buffer,
- tempObjectFile);
- }
-#endif
-
- if (result == 0) {
- /* Generate the library file. */
- result = pkg_generateLibraryFile(targetDir, mode, buffer, cmd);
- }
- uprv_free(buffer);
- uprv_free(cmd);
-
- return result;
-}
-#endif
-
-#ifdef WINDOWS_WITH_MSVC
-#define LINK_CMD "link.exe /nologo /release /out:"
-#define LINK_FLAGS "/DLL /NOENTRY /MANIFEST:NO /base:0x4ad00000 /implib:"
-#define LIB_CMD "LIB.exe /nologo /out:"
-#define LIB_FILE "icudt.lib"
-#define LIB_EXT UDATA_LIB_SUFFIX
-#define DLL_EXT UDATA_SO_SUFFIX
-
-static int32_t pkg_createWindowsDLL(const char mode, const char *gencFilePath, UPKGOptions *o) {
- char cmd[LARGE_BUFFER_MAX_SIZE];
- if (mode == MODE_STATIC) {
- char staticLibFilePath[SMALL_BUFFER_MAX_SIZE] = "";
-
- uprv_strcpy(staticLibFilePath, o->tmpDir);
- uprv_strcat(staticLibFilePath, PKGDATA_FILE_SEP_STRING);
-
- uprv_strcat(staticLibFilePath, o->entryName);
- uprv_strcat(staticLibFilePath, LIB_EXT);
-
- sprintf(cmd, "%s\"%s\" \"%s\"",
- LIB_CMD,
- staticLibFilePath,
- gencFilePath);
- } else if (mode == MODE_DLL) {
- char dllFilePath[SMALL_BUFFER_MAX_SIZE] = "";
- char libFilePath[SMALL_BUFFER_MAX_SIZE] = "";
- char resFilePath[SMALL_BUFFER_MAX_SIZE] = "";
-
-#ifdef CYGWINMSVC
- uprv_strcpy(dllFilePath, o->targetDir);
-#else
- uprv_strcpy(dllFilePath, o->srcDir);
-#endif
- uprv_strcat(dllFilePath, PKGDATA_FILE_SEP_STRING);
- uprv_strcpy(libFilePath, dllFilePath);
-
- uprv_strcpy(resFilePath, o->tmpDir);
- uprv_strcat(resFilePath, PKGDATA_FILE_SEP_STRING);
-
- uprv_strcat(dllFilePath, o->entryName);
- uprv_strcat(dllFilePath, DLL_EXT);
- uprv_strcat(libFilePath, LIB_FILE);
- uprv_strcat(resFilePath, ICUDATA_RES_FILE);
-
- if (!T_FileStream_file_exists(resFilePath)) {
- uprv_memset(resFilePath, 0, sizeof(resFilePath));
- }
-
- /* Check if dll file and lib file exists and that it is not newer than genc file. */
- if (!o->rebuild && (T_FileStream_file_exists(dllFilePath) && isFileModTimeLater(dllFilePath, gencFilePath)) &&
- (T_FileStream_file_exists(libFilePath) && isFileModTimeLater(libFilePath, gencFilePath))) {
- return 0;
- }
-
- sprintf(cmd, "%s\"%s\" %s\"%s\" \"%s\" \"%s\"",
- LINK_CMD,
- dllFilePath,
- LINK_FLAGS,
- libFilePath,
- gencFilePath,
- resFilePath
- );
- }
-
- return system(cmd);
-}
-#endif
-
-static void pkg_checkFlag(UPKGOptions *o) {
-#ifdef U_AIX
- /* AIX needs a map file. */
- char *flag = NULL;
- int32_t length = 0;
- char tmpbuffer[SMALL_BUFFER_MAX_SIZE];
- const char MAP_FILE_EXT[] = ".map";
- FileStream *f = NULL;
- char mapFile[SMALL_BUFFER_MAX_SIZE] = "";
- int32_t start = -1;
- int32_t count = 0;
-
- flag = pkgDataFlags[BIR_FLAGS];
- length = uprv_strlen(pkgDataFlags[BIR_FLAGS]);
-
- for (int32_t i = 0; i < length; i++) {
- if (flag[i] == MAP_FILE_EXT[count]) {
- if (count == 0) {
- start = i;
- }
- count++;
- } else {
- count = 0;
- }
-
- if (count == uprv_strlen(MAP_FILE_EXT)) {
- break;
- }
- }
-
- if (start >= 0) {
- int32_t index = 0;
- for (int32_t i = 0;;i++) {
- if (i == start) {
- for (int32_t n = 0;;n++) {
- if (o->shortName[n] == 0) {
- break;
- }
- tmpbuffer[index++] = o->shortName[n];
- }
- }
-
- tmpbuffer[index++] = flag[i];
-
- if (flag[i] == 0) {
- break;
- }
- }
-
- uprv_memset(flag, 0, length);
- uprv_strcpy(flag, tmpbuffer);
-
- uprv_strcpy(mapFile, o->shortName);
- uprv_strcat(mapFile, MAP_FILE_EXT);
-
- f = T_FileStream_open(mapFile, "w");
- if (f == NULL) {
- fprintf(stderr,"Unable to create map file: %s.\n", mapFile);
- return;
- }
-
- sprintf(tmpbuffer, "%s%s ", o->entryName, UDATA_CMN_INTERMEDIATE_SUFFIX);
-
- T_FileStream_writeLine(f, tmpbuffer);
-
- T_FileStream_close(f);
- }
-#elif defined(U_CYGWIN)
- /* Cygwin needs to change flag options. */
- char *flag = NULL;
- int32_t length = 0;
-
- flag = pkgDataFlags[GENLIB];
- length = uprv_strlen(pkgDataFlags[GENLIB]);
-
- int32_t position = length - 1;
-
- for(;position >= 0;position--) {
- if (flag[position] == '=') {
- position++;
- break;
- }
- }
-
- uprv_memset(flag + position, 0, length - position);
-#elif defined(OS400)
- /* OS400 needs to fix the ld options (swap single quote with double quote) */
- char *flag = NULL;
- int32_t length = 0;
-
- flag = pkgDataFlags[GENLIB];
- length = uprv_strlen(pkgDataFlags[GENLIB]);
-
- int32_t position = length - 1;
-
- for(int32_t i = 0; i < length; i++) {
- if (flag[i] == '\'') {
- flag[i] = '\"';
- }
- }
-#endif
-}
-
-static void loadLists(UPKGOptions *o, UErrorCode *status)
-{
- CharList *l, *tail = NULL, *tail2 = NULL;
- FileStream *in;
- char line[16384];
- char *linePtr, *lineNext;
- const uint32_t lineMax = 16300;
- char tmp[1024];
- char *s;
- int32_t ln=0; /* line number */
-
- for(l = o->fileListFiles; l; l = l->next) {
- if(o->verbose) {
- fprintf(stdout, "# Reading %s..\n", l->str);
- }
- /* TODO: stdin */
- in = T_FileStream_open(l->str, "r"); /* open files list */
-
- if(!in) {
- fprintf(stderr, "Error opening <%s>.\n", l->str);
- *status = U_FILE_ACCESS_ERROR;
- return;
- }
-
- while(T_FileStream_readLine(in, line, sizeof(line))!=NULL) { /* for each line */
- ln++;
- if(uprv_strlen(line)>lineMax) {
- fprintf(stderr, "%s:%d - line too long (over %d chars)\n", l->str, (int)ln, (int)lineMax);
- exit(1);
- }
- /* remove spaces at the beginning */
- linePtr = line;
- while(isspace(*linePtr)) {
- linePtr++;
- }
- s=linePtr;
- /* remove trailing newline characters */
- while(*s!=0) {
- if(*s=='\r' || *s=='\n') {
- *s=0;
- break;
- }
- ++s;
- }
- if((*linePtr == 0) || (*linePtr == '#')) {
- continue; /* comment or empty line */
- }
-
- /* Now, process the line */
- lineNext = NULL;
-
- while(linePtr && *linePtr) { /* process space-separated items */
- while(*linePtr == ' ') {
- linePtr++;
- }
- /* Find the next quote */
- if(linePtr[0] == '"')
- {
- lineNext = uprv_strchr(linePtr+1, '"');
- if(lineNext == NULL) {
- fprintf(stderr, "%s:%d - missing trailing double quote (\")\n",
- l->str, (int)ln);
- exit(1);
- } else {
- lineNext++;
- if(*lineNext) {
- if(*lineNext != ' ') {
- fprintf(stderr, "%s:%d - malformed quoted line at position %d, expected ' ' got '%c'\n",
- l->str, (int)ln, (int)(lineNext-line), (*lineNext)?*lineNext:'0');
- exit(1);
- }
- *lineNext = 0;
- lineNext++;
- }
- }
- } else {
- lineNext = uprv_strchr(linePtr, ' ');
- if(lineNext) {
- *lineNext = 0; /* terminate at space */
- lineNext++;
- }
- }
-
- /* add the file */
- s = (char*)getLongPathname(linePtr);
-
- /* normal mode.. o->files is just the bare list without package names */
- o->files = pkg_appendToList(o->files, &tail, uprv_strdup(linePtr));
- if(uprv_pathIsAbsolute(s)) {
- fprintf(stderr, "pkgdata: Error: absolute path encountered. Old style paths are not supported. Use relative paths such as 'fur.res' or 'translit%cfur.res'.\n\tBad path: '%s'\n", U_FILE_SEP_CHAR, s);
- exit(U_ILLEGAL_ARGUMENT_ERROR);
- }
- uprv_strcpy(tmp, o->srcDir);
- uprv_strcat(tmp, o->srcDir[uprv_strlen(o->srcDir)-1] == U_FILE_SEP_CHAR ? "" :PKGDATA_FILE_SEP_STRING);
- uprv_strcat(tmp, s);
- o->filePaths = pkg_appendToList(o->filePaths, &tail2, uprv_strdup(tmp));
- linePtr = lineNext;
- } /* for each entry on line */
- } /* for each line */
- T_FileStream_close(in);
- } /* for each file list file */
-}
-
-/* Try calling icu-config directly to get the option file. */
-static int32_t pkg_getOptionsFromICUConfig(UOption *option) {
-#if U_HAVE_POPEN
- FILE *p;
- size_t n;
- static char buf[512] = "";
- const char cmd[] = "icu-config --incpkgdatafile";
-
- p = popen(cmd, "r");
-
- if(p == NULL)
- {
- fprintf(stderr, "%s: icu-config: No icu-config found. (fix PATH or use -O option)\n", progname);
- return -1;
- }
-
- n = fread(buf, 1, 511, p);
-
- pclose(p);
-
- if(n<=0)
- {
- fprintf(stderr,"%s: icu-config: Could not read from icu-config. (fix PATH or use -O option)\n", progname);
- return -1;
- }
-
- for (int32_t length = strlen(buf) - 1; length >= 0; length--) {
- if (buf[length] == '\n' || buf[length] == ' ') {
- buf[length] = 0;
- } else {
- break;
- }
- }
-
- if(buf[strlen(buf)-1]=='\n')
- {
- buf[strlen(buf)-1]=0;
- }
-
- if(buf[0] == 0)
- {
- fprintf(stderr, "%s: icu-config: invalid response from icu-config (fix PATH or use -O option)\n", progname);
- return -1;
- }
-
- option->value = buf;
- option->doesOccur = TRUE;
-
- return 0;
-#endif
- return -1;
-}
+/******************************************************************************
+ * Copyright (C) 2000-2009, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *******************************************************************************
+ * file name: pkgdata.c
+ * encoding: ANSI X3.4 (1968)
+ * tab size: 8 (not used)
+ * indentation:4
+ *
+ * created on: 2000may15
+ * created by: Steven \u24C7 Loomis
+ *
+ * This program packages the ICU data into different forms
+ * (DLL, common data, etc.)
+ */
+
+/*
+ * We define _XOPEN_SOURCE so that we can get popen and pclose.
+ */
+#if !defined(_XOPEN_SOURCE)
+#if __STDC_VERSION__ >= 199901L
+/* It is invalid to compile an XPG3, XPG4, XPG4v2 or XPG5 application using c99 on Solaris */
+#define _XOPEN_SOURCE 600
+#else
+#define _XOPEN_SOURCE 4
+#endif
+#endif
+
+
+#include "unicode/utypes.h"
+
+#if U_HAVE_POPEN
+#if defined(U_CYGWIN) && defined(__STRICT_ANSI__)
+/* popen/pclose aren't defined in strict ANSI on Cygwin */
+#undef __STRICT_ANSI__
+#endif
+#endif
+
+#include "unicode/putil.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "filestrm.h"
+#include "toolutil.h"
+#include "unicode/uclean.h"
+#include "unewdata.h"
+#include "uoptions.h"
+#include "putilimp.h"
+#include "package.h"
+#include "pkg_icu.h"
+#include "pkg_genc.h"
+#include "pkg_gencmn.h"
+#include "flagparser.h"
+#include "filetools.h"
+
+
+#if U_HAVE_POPEN
+# include <unistd.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+
+U_CDECL_BEGIN
+#include "pkgtypes.h"
+U_CDECL_END
+
+#ifdef U_WINDOWS
+#ifdef __GNUC__
+#define WINDOWS_WITH_GNUC
+#else
+#define WINDOWS_WITH_MSVC
+#endif
+#endif
+#if !defined(WINDOWS_WITH_MSVC) && !defined(U_LINUX)
+#define BUILD_DATA_WITHOUT_ASSEMBLY
+#endif
+#if defined(WINDOWS_WITH_MSVC) || defined(U_LINUX)
+#define CAN_WRITE_OBJ_CODE
+#endif
+
+/*
+ * When building the data library without assembly,
+ * some platforms use a single c code file for all of
+ * the data to generate the final data library. This can
+ * increase the performance of the pkdata tool.
+ */
+#if defined(OS400)
+#define USE_SINGLE_CCODE_FILE
+#endif
+
+/* Need to fix the file seperator character when using MinGW. */
+#ifdef WINDOWS_WITH_GNUC
+#define PKGDATA_FILE_SEP_STRING "/"
+#else
+#define PKGDATA_FILE_SEP_STRING U_FILE_SEP_STRING
+#endif
+
+#define LARGE_BUFFER_MAX_SIZE 2048
+#define SMALL_BUFFER_MAX_SIZE 512
+
+static void loadLists(UPKGOptions *o, UErrorCode *status);
+
+static int32_t pkg_executeOptions(UPKGOptions *o);
+
+#ifdef WINDOWS_WITH_MSVC
+static int32_t pkg_createWindowsDLL(const char mode, const char *gencFilePath, UPKGOptions *o);
+#endif
+static int32_t pkg_createSymLinks(const char *targetDir);
+static int32_t pkg_installLibrary(const char *installDir, const char *dir);
+static int32_t pkg_installFileMode(const char *installDir, const char *srcDir, const char *fileListName);
+
+#ifdef BUILD_DATA_WITHOUT_ASSEMBLY
+static int32_t pkg_createWithoutAssemblyCode(UPKGOptions *o, const char *targetDir, const char mode);
+#endif
+
+static int32_t pkg_createWithAssemblyCode(const char *targetDir, const char mode, const char *gencFilePath);
+static int32_t pkg_generateLibraryFile(const char *targetDir, const char mode, const char *objectFile, char *command = NULL);
+static int32_t pkg_archiveLibrary(const char *targetDir, const char *version, UBool reverseExt);
+static void createFileNames(const char *version_major, const char *version, const char *libName, const UBool reverseExt);
+
+static int32_t pkg_getOptionsFromICUConfig(UOption *option);
+
+enum {
+ NAME,
+ BLDOPT,
+ MODE,
+ HELP,
+ HELP_QUESTION_MARK,
+ VERBOSE,
+ COPYRIGHT,
+ COMMENT,
+ DESTDIR,
+ REBUILD,
+ TEMPDIR,
+ INSTALL,
+ SOURCEDIR,
+ ENTRYPOINT,
+ REVISION,
+ FORCE_PREFIX,
+ LIBNAME,
+ QUIET
+};
+
+/* This sets the modes that are available */
+static struct {
+ const char *name, *alt_name;
+ const char *desc;
+} modes[] = {
+ { "files", 0, "Uses raw data files (no effect). Installation copies all files to the target location." },
+#ifdef U_WINDOWS
+ { "dll", "library", "Generates one common data file and one shared library, <package>.dll"},
+ { "common", "archive", "Generates just the common file, <package>.dat"},
+ { "static", "static", "Generates one statically linked library, " LIB_PREFIX "<package>" UDATA_LIB_SUFFIX }
+#else
+#ifdef UDATA_SO_SUFFIX
+ { "dll", "library", "Generates one shared library, <package>" UDATA_SO_SUFFIX },
+#endif
+ { "common", "archive", "Generates one common data file, <package>.dat" },
+ { "static", "static", "Generates one statically linked library, " LIB_PREFIX "<package>" UDATA_LIB_SUFFIX }
+#endif
+};
+
+static UOption options[]={
+ /*00*/ UOPTION_DEF( "name", 'p', UOPT_REQUIRES_ARG),
+ /*01*/ UOPTION_DEF( "bldopt", 'O', UOPT_REQUIRES_ARG), /* on Win32 it is release or debug */
+ /*02*/ UOPTION_DEF( "mode", 'm', UOPT_REQUIRES_ARG),
+ /*03*/ UOPTION_HELP_H, /* -h */
+ /*04*/ UOPTION_HELP_QUESTION_MARK, /* -? */
+ /*05*/ UOPTION_VERBOSE, /* -v */
+ /*06*/ UOPTION_COPYRIGHT, /* -c */
+ /*07*/ UOPTION_DEF( "comment", 'C', UOPT_REQUIRES_ARG),
+ /*08*/ UOPTION_DESTDIR, /* -d */
+ /*11*/ UOPTION_DEF( "rebuild", 'F', UOPT_NO_ARG),
+ /*12*/ UOPTION_DEF( "tempdir", 'T', UOPT_REQUIRES_ARG),
+ /*13*/ UOPTION_DEF( "install", 'I', UOPT_REQUIRES_ARG),
+ /*14*/ UOPTION_SOURCEDIR ,
+ /*15*/ UOPTION_DEF( "entrypoint", 'e', UOPT_REQUIRES_ARG),
+ /*16*/ UOPTION_DEF( "revision", 'r', UOPT_REQUIRES_ARG),
+ /*17*/ UOPTION_DEF( "force-prefix", 'f', UOPT_NO_ARG),
+ /*18*/ UOPTION_DEF( "libname", 'L', UOPT_REQUIRES_ARG),
+ /*19*/ UOPTION_DEF( "quiet", 'q', UOPT_NO_ARG)
+};
+
+enum {
+ GENCCODE_ASSEMBLY_TYPE,
+ SO_EXT,
+ SOBJ_EXT,
+ A_EXT,
+ LIBPREFIX,
+ LIB_EXT_ORDER,
+ COMPILER,
+ LIBFLAGS,
+ GENLIB,
+ LDICUDTFLAGS,
+ LD_SONAME,
+ RPATH_FLAGS,
+ BIR_FLAGS,
+ AR,
+ ARFLAGS,
+ RANLIB,
+ INSTALL_CMD,
+ PKGDATA_FLAGS_SIZE
+};
+static char **pkgDataFlags = NULL;
+
+enum {
+ LIB_FILE,
+ LIB_FILE_VERSION_MAJOR,
+ LIB_FILE_VERSION,
+ LIB_FILE_VERSION_TMP,
+#ifdef U_CYGWIN
+ LIB_FILE_CYGWIN,
+#endif
+ LIB_FILENAMES_SIZE
+};
+static char libFileNames[LIB_FILENAMES_SIZE][256];
+
+static void pkg_checkFlag(UPKGOptions *o);
+
+const char options_help[][320]={
+ "Set the data name",
+#ifdef U_MAKE_IS_NMAKE
+ "The directory where the ICU is located (e.g. <ICUROOT> which contains the bin directory)",
+#else
+ "Specify options for the builder.",
+#endif
+ "Specify the mode of building (see below; default: common)",
+ "This usage text",
+ "This usage text",
+ "Make the output verbose",
+ "Use the standard ICU copyright",
+ "Use a custom comment (instead of the copyright)",
+ "Specify the destination directory for files",
+ "Force rebuilding of all data",
+ "Specify temporary dir (default: output dir)",
+ "Install the data (specify target)",
+ "Specify a custom source directory",
+ "Specify a custom entrypoint name (default: short name)",
+ "Specify a version when packaging in DLL or static mode",
+ "Add package to all file names if not present",
+ "Library name to build (if different than package name)",
+ "Quite mode. (e.g. Do not output a readme file for static libraries)"
+};
+
+const char *progname = "PKGDATA";
+
+int
+main(int argc, char* argv[]) {
+ int result = 0;
+ /* FileStream *out; */
+ UPKGOptions o;
+ CharList *tail;
+ UBool needsHelp = FALSE;
+ UErrorCode status = U_ZERO_ERROR;
+ /* char tmp[1024]; */
+ uint32_t i;
+ int32_t n;
+
+ U_MAIN_INIT_ARGS(argc, argv);
+
+ progname = argv[0];
+
+ options[MODE].value = "common";
+
+ /* read command line options */
+ argc=u_parseArgs(argc, argv, sizeof(options)/sizeof(options[0]), options);
+
+ /* error handling, printing usage message */
+ /* I've decided to simply print an error and quit. This tool has too
+ many options to just display them all of the time. */
+
+ if(options[HELP].doesOccur || options[HELP_QUESTION_MARK].doesOccur) {
+ needsHelp = TRUE;
+ }
+ else {
+ if(!needsHelp && argc<0) {
+ fprintf(stderr,
+ "%s: error in command line argument \"%s\"\n",
+ progname,
+ argv[-argc]);
+ fprintf(stderr, "Run '%s --help' for help.\n", progname);
+ return 1;
+ }
+
+
+#ifndef WINDOWS_WITH_MSVC
+ if(!options[BLDOPT].doesOccur) {
+ if (pkg_getOptionsFromICUConfig(&options[BLDOPT]) != 0) {
+ fprintf(stderr, " required parameter is missing: -O is required \n");
+ fprintf(stderr, "Run '%s --help' for help.\n", progname);
+ return 1;
+ }
+ }
+#else
+ if(options[BLDOPT].doesOccur) {
+ fprintf(stdout, "Warning: You are using the -O option which is not needed for MSVC build on Windows.\n");
+ }
+#endif
+
+ if(!options[NAME].doesOccur) /* -O we already have - don't report it. */
+ {
+ fprintf(stderr, " required parameter -p is missing \n");
+ fprintf(stderr, "Run '%s --help' for help.\n", progname);
+ return 1;
+ }
+
+ if(argc == 1) {
+ fprintf(stderr,
+ "No input files specified.\n"
+ "Run '%s --help' for help.\n", progname);
+ return 1;
+ }
+ } /* end !needsHelp */
+
+ if(argc<0 || needsHelp ) {
+ fprintf(stderr,
+ "usage: %s [-options] [-] [packageFile] \n"
+ "\tProduce packaged ICU data from the given list(s) of files.\n"
+ "\t'-' by itself means to read from stdin.\n"
+ "\tpackageFile is a text file containing the list of files to package.\n",
+ progname);
+
+ fprintf(stderr, "\n options:\n");
+ for(i=0;i<(sizeof(options)/sizeof(options[0]));i++) {
+ fprintf(stderr, "%-5s -%c %s%-10s %s\n",
+ (i<1?"[REQ]":""),
+ options[i].shortName,
+ options[i].longName ? "or --" : " ",
+ options[i].longName ? options[i].longName : "",
+ options_help[i]);
+ }
+
+ fprintf(stderr, "modes: (-m option)\n");
+ for(i=0;i<(sizeof(modes)/sizeof(modes[0]));i++) {
+ fprintf(stderr, " %-9s ", modes[i].name);
+ if (modes[i].alt_name) {
+ fprintf(stderr, "/ %-9s", modes[i].alt_name);
+ } else {
+ fprintf(stderr, " ");
+ }
+ fprintf(stderr, " %s\n", modes[i].desc);
+ }
+ return 1;
+ }
+
+ /* OK, fill in the options struct */
+ uprv_memset(&o, 0, sizeof(o));
+
+ o.mode = options[MODE].value;
+ o.version = options[REVISION].doesOccur ? options[REVISION].value : 0;
+
+ o.shortName = options[NAME].value;
+ {
+ int32_t len = (int32_t)uprv_strlen(o.shortName);
+ char *csname, *cp;
+ const char *sp;
+
+ cp = csname = (char *) uprv_malloc((len + 1 + 1) * sizeof(*o.cShortName));
+ if (*(sp = o.shortName)) {
+ *cp++ = isalpha(*sp) ? * sp : '_';
+ for (++sp; *sp; ++sp) {
+ *cp++ = isalnum(*sp) ? *sp : '_';
+ }
+ }
+ *cp = 0;
+
+ o.cShortName = csname;
+ }
+
+ if(options[LIBNAME].doesOccur) { /* get libname from shortname, or explicit -L parameter */
+ o.libName = options[LIBNAME].value;
+ } else {
+ o.libName = o.shortName;
+ }
+
+ if(options[QUIET].doesOccur) {
+ o.quiet = TRUE;
+ } else {
+ o.quiet = FALSE;
+ }
+
+ o.verbose = options[VERBOSE].doesOccur;
+
+#ifndef WINDOWS_WITH_MSVC /* on UNIX, we'll just include the file... */
+ o.options = options[BLDOPT].value;
+#endif
+ if(options[COPYRIGHT].doesOccur) {
+ o.comment = U_COPYRIGHT_STRING;
+ } else if (options[COMMENT].doesOccur) {
+ o.comment = options[COMMENT].value;
+ }
+
+ if( options[DESTDIR].doesOccur ) {
+ o.targetDir = options[DESTDIR].value;
+ } else {
+ o.targetDir = "."; /* cwd */
+ }
+
+ o.rebuild = options[REBUILD].doesOccur;
+
+ if( options[TEMPDIR].doesOccur ) {
+ o.tmpDir = options[TEMPDIR].value;
+ } else {
+ o.tmpDir = o.targetDir;
+ }
+
+ if( options[INSTALL].doesOccur ) {
+ o.install = options[INSTALL].value;
+ } else {
+ o.install = NULL;
+ }
+
+ if( options[SOURCEDIR].doesOccur ) {
+ o.srcDir = options[SOURCEDIR].value;
+ } else {
+ o.srcDir = ".";
+ }
+
+ if( options[ENTRYPOINT].doesOccur ) {
+ o.entryName = options[ENTRYPOINT].value;
+ } else {
+ o.entryName = o.cShortName;
+ }
+
+ /* OK options are set up. Now the file lists. */
+ tail = NULL;
+ for( n=1; n<argc; n++) {
+ o.fileListFiles = pkg_appendToList(o.fileListFiles, &tail, uprv_strdup(argv[n]));
+ }
+
+ /* load the files */
+ loadLists(&o, &status);
+ if( U_FAILURE(status) ) {
+ fprintf(stderr, "error loading input file lists: %s\n", u_errorName(status));
+ return 2;
+ }
+
+ result = pkg_executeOptions(&o);
+
+ if (pkgDataFlags != NULL) {
+ for (n = 0; n < PKGDATA_FLAGS_SIZE; n++) {
+ if (pkgDataFlags[n] != NULL) {
+ uprv_free(pkgDataFlags[n]);
+ }
+ }
+ uprv_free(pkgDataFlags);
+ }
+
+ if (o.cShortName != NULL) {
+ uprv_free((char *)o.cShortName);
+ }
+ if (o.fileListFiles != NULL) {
+ pkg_deleteList(o.fileListFiles);
+ }
+ if (o.filePaths != NULL) {
+ pkg_deleteList(o.filePaths);
+ }
+ if (o.files != NULL) {
+ pkg_deleteList(o.files);
+ }
+
+ return result;
+}
+
+#define LN_CMD "ln -s"
+#define RM_CMD "rm -f"
+
+#define MODE_COMMON 'c'
+#define MODE_STATIC 's'
+#define MODE_DLL 'd'
+#define MODE_FILES 'f'
+
+static int32_t pkg_executeOptions(UPKGOptions *o) {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t result = 0;
+// char cmd[SMALL_BUFFER_MAX_SIZE] = "";
+ const char mode = o->mode[0];
+ char targetDir[SMALL_BUFFER_MAX_SIZE] = "";
+ char tmpDir[SMALL_BUFFER_MAX_SIZE] = "";
+ char datFileName[SMALL_BUFFER_MAX_SIZE] = "";
+ char datFileNamePath[LARGE_BUFFER_MAX_SIZE] = "";
+ char checkLibFile[LARGE_BUFFER_MAX_SIZE] = "";
+
+ /* Initialize pkgdataFlags */
+ pkgDataFlags = (char**)uprv_malloc(sizeof(char*) * PKGDATA_FLAGS_SIZE);
+ if (pkgDataFlags != NULL) {
+ for (int32_t i = 0; i < PKGDATA_FLAGS_SIZE; i++) {
+ pkgDataFlags[i] = (char*)uprv_malloc(sizeof(char) * SMALL_BUFFER_MAX_SIZE);
+ if (pkgDataFlags[i] != NULL) {
+ pkgDataFlags[i][0] = 0;
+ } else {
+ fprintf(stderr,"Error allocating memory for pkgDataFlags.\n");
+ return -1;
+ }
+ }
+ } else {
+ fprintf(stderr,"Error allocating memory for pkgDataFlags.\n");
+ return -1;
+ }
+#ifndef WINDOWS_WITH_MSVC
+ /* Read in options file. */
+ parseFlagsFile(o->options, pkgDataFlags, SMALL_BUFFER_MAX_SIZE, (int32_t)PKGDATA_FLAGS_SIZE, &status);
+ if (U_FAILURE(status)) {
+ fprintf(stderr,"Unable to open or read \"%s\" option file.\n", o->options);
+ return -1;
+ }
+#endif
+ if (mode == MODE_FILES) {
+ /* Copy the raw data to the installation directory. */
+ if (o->install != NULL) {
+ uprv_strcpy(targetDir, o->install);
+ if (o->shortName != NULL) {
+ uprv_strcat(targetDir, PKGDATA_FILE_SEP_STRING);
+ uprv_strcat(targetDir, o->shortName);
+ }
+ result = pkg_installFileMode(targetDir, o->srcDir, o->fileListFiles->str);
+ }
+ return result;
+ } else /* if (mode == MODE_COMMON || mode == MODE_STATIC || mode == MODE_DLL) */ {
+ uprv_strcpy(targetDir, o->targetDir);
+ uprv_strcat(targetDir, PKGDATA_FILE_SEP_STRING);
+
+ uprv_strcpy(tmpDir, o->tmpDir);
+ uprv_strcat(tmpDir, PKGDATA_FILE_SEP_STRING);
+
+ uprv_strcpy(datFileNamePath, tmpDir);
+
+ uprv_strcpy(datFileName, o->shortName);
+ uprv_strcat(datFileName, UDATA_CMN_SUFFIX);
+
+ uprv_strcat(datFileNamePath, datFileName);
+
+ result = writePackageDatFile(datFileNamePath, o->comment, o->srcDir, o->fileListFiles->str, NULL, U_IS_BIG_ENDIAN ? 'b' : 'l');
+ if (result != 0) {
+ fprintf(stderr,"Error writing package dat file.\n");
+ return result;
+ }
+
+ if (mode == MODE_COMMON) {
+ char targetFileNamePath[LARGE_BUFFER_MAX_SIZE] = "";
+
+ uprv_strcpy(targetFileNamePath, targetDir);
+ uprv_strcat(targetFileNamePath, datFileName);
+
+ if (T_FileStream_file_exists(targetFileNamePath)) {
+ if ((result = remove(targetFileNamePath)) != 0) {
+ fprintf(stderr, "Unable to remove old dat file: %s\n", targetFileNamePath);
+ return result;
+ }
+ }
+
+ /* Move the dat file created to the target directory. */
+ result = rename(datFileNamePath, targetFileNamePath);
+ if (result != 0) {
+ fprintf(stderr, "Unable to move dat file (%s) to target location (%s).\n", datFileNamePath, targetFileNamePath);
+ }
+
+ return result;
+ } else /* if (mode[0] == MODE_STATIC || mode[0] == MODE_DLL) */ {
+ char gencFilePath[SMALL_BUFFER_MAX_SIZE] = "";
+ char version_major[10] = "";
+ UBool reverseExt = FALSE;
+
+#ifndef WINDOWS_WITH_MSVC
+ /* Get the version major number. */
+ if (o->version != NULL) {
+ for (uint32_t i = 0;i < sizeof(version_major);i++) {
+ if (o->version[i] == '.') {
+ version_major[i] = 0;
+ break;
+ }
+ version_major[i] = o->version[i];
+ }
+ }
+
+#ifndef OS400
+ /* Certain platforms have different library extension ordering. (e.g. libicudata.##.so vs libicudata.so.##)
+ * reverseExt is FALSE if the suffix should be the version number.
+ */
+ if (pkgDataFlags[LIB_EXT_ORDER][uprv_strlen(pkgDataFlags[LIB_EXT_ORDER])-1] == pkgDataFlags[SO_EXT][uprv_strlen(pkgDataFlags[SO_EXT])-1]) {
+ reverseExt = TRUE;
+ }
+#endif
+ /* Using the base libName and version number, generate the library file names. */
+ createFileNames(version_major, o->version, o->libName, reverseExt);
+
+ if (o->version != 0 && o->rebuild == FALSE) {
+ /* Check to see if a previous built data library file exists and check if it is the latest. */
+ sprintf(checkLibFile, "%s%s", targetDir, libFileNames[LIB_FILE_VERSION_TMP]);
+ if (T_FileStream_file_exists(checkLibFile)) {
+ if (isFileModTimeLater(checkLibFile, o->srcDir, TRUE) && isFileModTimeLater(checkLibFile, o->options)) {
+ if (o->install != NULL) {
+ uprv_strcpy(libFileNames[LIB_FILE_VERSION], libFileNames[LIB_FILE_VERSION_TMP]);
+ result = pkg_installLibrary(o->install, targetDir);
+ }
+ return result;
+ }
+ }
+ }
+
+ pkg_checkFlag(o);
+#endif
+
+ if (pkgDataFlags[GENCCODE_ASSEMBLY_TYPE][0] != 0) {
+ const char* genccodeAssembly = pkgDataFlags[GENCCODE_ASSEMBLY_TYPE];
+
+ /* Offset genccodeAssembly by 3 because "-a " */
+ if (checkAssemblyHeaderName(genccodeAssembly+3)) {
+ writeAssemblyCode(datFileNamePath, o->tmpDir, o->entryName, NULL, gencFilePath);
+
+ result = pkg_createWithAssemblyCode(targetDir, mode, gencFilePath);
+ if (result != 0) {
+ fprintf(stderr, "Error generating assembly code for data.\n");
+ return result;
+ } else if (mode == MODE_STATIC) {
+ return result;
+ }
+ } else {
+ fprintf(stderr,"Assembly type \"%s\" is unknown.\n", genccodeAssembly);
+ return -1;
+ }
+ } else {
+#ifdef CAN_WRITE_OBJ_CODE
+ writeObjectCode(datFileNamePath, o->tmpDir, o->entryName, NULL, NULL, gencFilePath);
+#ifdef U_LINUX
+ result = pkg_generateLibraryFile(targetDir, mode, gencFilePath);
+#elif defined(WINDOWS_WITH_MSVC)
+ return pkg_createWindowsDLL(mode, gencFilePath, o);
+#endif
+#elif defined(BUILD_DATA_WITHOUT_ASSEMBLY)
+ result = pkg_createWithoutAssemblyCode(o, targetDir, mode);
+#endif
+ if (result != 0) {
+ fprintf(stderr, "Error generating package data.\n");
+ return result;
+ }
+ }
+#ifndef U_WINDOWS
+ /* Certain platforms uses archive library. (e.g. AIX) */
+ result = pkg_archiveLibrary(targetDir, o->version, reverseExt);
+ if (result != 0) {
+ fprintf(stderr, "Error creating data archive library file.\n");
+ return result;
+ }
+#ifndef OS400
+ /* Create symbolic links for the final library file. */
+ result = pkg_createSymLinks(targetDir);
+ if (result != 0) {
+ fprintf(stderr, "Error creating symbolic links of the data library file.\n");
+ return result;
+ }
+#endif
+ /* Install the libraries if option was set. */
+ if (o->install != NULL) {
+ result = pkg_installLibrary(o->install, targetDir);
+ if (result != 0) {
+ fprintf(stderr, "Error installing the data library.\n");
+ return result;
+ }
+ }
+#endif
+ }
+ }
+ return result;
+}
+/*
+ * Given the base libName and version numbers, generate the libary file names and store it in libFileNames.
+ * Depending on the configuration, the library name may either end with version number or shared object suffix.
+ */
+static void createFileNames(const char *version_major, const char *version, const char *libName, UBool reverseExt) {
+ sprintf(libFileNames[LIB_FILE], "%s%s",
+ pkgDataFlags[LIBPREFIX],
+ libName);
+ if (version != NULL) {
+#ifdef U_CYGWIN
+ sprintf(libFileNames[LIB_FILE_CYGWIN], "cyg%s%s.%s",
+ libName,
+ version_major,
+ pkgDataFlags[SO_EXT]);
+
+ sprintf(pkgDataFlags[SO_EXT], "%s.%s",
+ pkgDataFlags[SO_EXT],
+ pkgDataFlags[A_EXT]);
+#elif defined(OS400)
+ sprintf(libFileNames[LIB_FILE_VERSION_TMP], "%s.%s",
+ libFileNames[LIB_FILE],
+ pkgDataFlags[SOBJ_EXT]);
+#else
+ sprintf(libFileNames[LIB_FILE_VERSION_TMP], "%s%s%s.%s",
+ libFileNames[LIB_FILE],
+ pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "",
+ reverseExt ? version : pkgDataFlags[SOBJ_EXT],
+ reverseExt ? pkgDataFlags[SOBJ_EXT] : version);
+#endif
+ sprintf(libFileNames[LIB_FILE_VERSION_MAJOR], "%s%s%s.%s",
+ libFileNames[LIB_FILE],
+ pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "",
+ reverseExt ? version_major : pkgDataFlags[SO_EXT],
+ reverseExt ? pkgDataFlags[SO_EXT] : version_major);
+
+ libFileNames[LIB_FILE_VERSION][0] = 0;
+
+#ifdef U_CYGWIN
+ /* Cygwin only deals with the version major number. */
+ uprv_strcpy(libFileNames[LIB_FILE_VERSION_TMP], libFileNames[LIB_FILE_VERSION_MAJOR]);
+#endif
+ }
+}
+
+/* Create the symbolic links for the final library file. */
+static int32_t pkg_createSymLinks(const char *targetDir) {
+ int32_t result = 0;
+ char cmd[LARGE_BUFFER_MAX_SIZE];
+
+#ifndef U_CYGWIN
+ /* No symbolic link to make. */
+ if (uprv_strlen(libFileNames[LIB_FILE_VERSION]) == 0 || uprv_strlen(libFileNames[LIB_FILE_VERSION_MAJOR]) == 0) {
+ return result;
+ }
+
+ sprintf(cmd, "cd %s && %s %s && %s %s %s",
+ targetDir,
+ RM_CMD,
+ libFileNames[LIB_FILE_VERSION_MAJOR],
+ LN_CMD,
+ libFileNames[LIB_FILE_VERSION],
+ libFileNames[LIB_FILE_VERSION_MAJOR]);
+ result = system(cmd);
+ if (result != 0) {
+ return result;
+ }
+#endif
+ sprintf(cmd, "cd %s && %s %s.%s && %s %s %s.%s",
+ targetDir,
+ RM_CMD,
+ libFileNames[LIB_FILE], pkgDataFlags[SO_EXT],
+ LN_CMD,
+ libFileNames[LIB_FILE_VERSION],
+ libFileNames[LIB_FILE], pkgDataFlags[SO_EXT]);
+
+ result = system(cmd);
+
+ return result;
+}
+
+static int32_t pkg_installLibrary(const char *installDir, const char *targetDir) {
+ int32_t result = 0;
+ char cmd[SMALL_BUFFER_MAX_SIZE];
+
+ sprintf(cmd, "cd %s && %s %s %s%s%s",
+ targetDir,
+ pkgDataFlags[INSTALL_CMD],
+ libFileNames[LIB_FILE_VERSION],
+ installDir, PKGDATA_FILE_SEP_STRING, libFileNames[LIB_FILE_VERSION]
+ );
+
+ result = system(cmd);
+
+ if (result != 0) {
+ return result;
+ }
+
+ return pkg_createSymLinks(installDir);
+}
+
+#ifdef U_WINDOWS_MSVC
+/* Copy commands for installing the raw data files on Windows. */
+#define WIN_INSTALL_CMD "xcopy"
+#define WIN_INSTALL_CMD_FLAGS "/E /Y /K"
+#endif
+static int32_t pkg_installFileMode(const char *installDir, const char *srcDir, const char *fileListName) {
+ int32_t result = 0;
+ char cmd[SMALL_BUFFER_MAX_SIZE] = "";
+
+ if (!T_FileStream_file_exists(installDir)) {
+ UErrorCode status = U_ZERO_ERROR;
+
+ uprv_mkdir(installDir, &status);
+ if (U_FAILURE(status)) {
+ fprintf(stderr, "Error creating installation directory: %s\n", installDir);
+ return -1;
+ }
+ }
+#ifndef U_WINDOWS_WITH_MSVC
+ char buffer[SMALL_BUFFER_MAX_SIZE] = "";
+
+ FileStream *f = T_FileStream_open(fileListName, "r");
+ if (f != NULL) {
+ for(;;) {
+ if (T_FileStream_readLine(f, buffer, SMALL_BUFFER_MAX_SIZE) != NULL) {
+ /* Remove new line character. */
+ buffer[uprv_strlen(buffer)-1] = 0;
+
+ sprintf(cmd, "%s %s%s%s %s%s%s",
+ pkgDataFlags[INSTALL_CMD],
+ srcDir, PKGDATA_FILE_SEP_STRING, buffer,
+ installDir, PKGDATA_FILE_SEP_STRING, buffer);
+
+ result = system(cmd);
+ if (result != 0) {
+ fprintf(stderr, "Failed to install data file with command: %s\n", cmd);
+ break;
+ }
+ } else {
+ if (!T_FileStream_eof(f)) {
+ fprintf(stderr, "Failed to read line from file: %s\n", fileListName);
+ result = -1;
+ }
+ break;
+ }
+ }
+ T_FileStream_close(f);
+ } else {
+ result = -1;
+ fprintf(stderr, "Unable to open list file: %s\n", fileListName);
+ }
+#else
+ sprintf(cmd, "%s %s %s %s", WIN_INSTALL_CMD, srcDir, installDir, WIN_INSTALL_CMD_FLAGS);
+ result = system(cmd);
+ if (result != 0) {
+ fprintf(stderr, "Failed to install data file with command: %s\n", cmd);
+ }
+#endif
+
+ return result;
+}
+
+/* Archiving of the library file may be needed depending on the platform and options given.
+ * If archiving is not needed, copy over the library file name.
+ */
+static int32_t pkg_archiveLibrary(const char *targetDir, const char *version, UBool reverseExt) {
+ int32_t result = 0;
+ char cmd[LARGE_BUFFER_MAX_SIZE];
+
+ /* If the shard object suffix and the final object suffix is different and the final object suffix and the
+ * archive file suffix is the same, then the final library needs to be archived.
+ */
+ if (uprv_strcmp(pkgDataFlags[SOBJ_EXT], pkgDataFlags[SO_EXT]) != 0 && uprv_strcmp(pkgDataFlags[A_EXT], pkgDataFlags[SO_EXT]) == 0) {
+ sprintf(libFileNames[LIB_FILE_VERSION], "%s%s%s.%s",
+ libFileNames[LIB_FILE],
+ pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "",
+ reverseExt ? version : pkgDataFlags[SO_EXT],
+ reverseExt ? pkgDataFlags[SO_EXT] : version);
+
+ sprintf(cmd, "%s %s %s%s %s%s",
+ pkgDataFlags[AR],
+ pkgDataFlags[ARFLAGS],
+ targetDir,
+ libFileNames[LIB_FILE_VERSION],
+ targetDir,
+ libFileNames[LIB_FILE_VERSION_TMP]);
+
+ result = system(cmd);
+ if (result != 0) {
+ return result;
+ }
+
+ /* Remove unneeded library file. */
+ sprintf(cmd, "%s %s%s",
+ RM_CMD,
+ targetDir,
+ libFileNames[LIB_FILE_VERSION_TMP]);
+
+ result = system(cmd);
+ if (result != 0) {
+ return result;
+ }
+
+ } else {
+ uprv_strcpy(libFileNames[LIB_FILE_VERSION], libFileNames[LIB_FILE_VERSION_TMP]);
+ }
+
+ return result;
+}
+
+/*
+ * Using the compiler information from the configuration file set by -O option, generate the library file.
+ * command may be given to allow for a larger buffer for cmd.
+ */
+static int32_t pkg_generateLibraryFile(const char *targetDir, const char mode, const char *objectFile, char *command) {
+ int32_t result = 0;
+ char *cmd = NULL;
+ UBool freeCmd = FALSE;
+
+ /* This is necessary because if packaging is done without assembly code, objectFile might be extremely large
+ * containing many object files and so the calling function should supply a command buffer that is large
+ * enough to handle this. Otherwise, use the default size.
+ */
+ if (command != NULL) {
+ cmd = command;
+ } else {
+ if ((cmd = (char *)uprv_malloc(sizeof(char) * LARGE_BUFFER_MAX_SIZE)) == NULL) {
+ fprintf(stderr, "Unable to allocate memory for command.\n");
+ return -1;
+ }
+ freeCmd = TRUE;
+ }
+
+ if (mode == MODE_STATIC) {
+#ifdef OS400
+ sprintf(cmd, "QSH CMD('%s %s %s%s.%s %s')",
+#else
+ sprintf(cmd, "%s %s %s%s.%s %s",
+#endif
+ pkgDataFlags[AR],
+ pkgDataFlags[ARFLAGS],
+ targetDir,
+ libFileNames[LIB_FILE],
+ pkgDataFlags[A_EXT],
+ objectFile);
+
+ result = system(cmd);
+ } else /* if (mode == MODE_DLL) */ {
+#ifdef U_CYGWIN
+ sprintf(cmd, "%s%s%s %s -o %s%s %s %s%s %s %s",
+ pkgDataFlags[GENLIB],
+ targetDir,
+ libFileNames[LIB_FILE_VERSION_TMP],
+ pkgDataFlags[LDICUDTFLAGS],
+ targetDir, libFileNames[LIB_FILE_CYGWIN],
+#else
+#ifdef OS400
+ sprintf(cmd, "QSH CMD('%s %s -o %s%s %s %s%s %s %s')",
+#else
+ sprintf(cmd, "%s %s -o %s%s %s %s%s %s %s",
+#endif
+ pkgDataFlags[GENLIB],
+ pkgDataFlags[LDICUDTFLAGS],
+ targetDir,
+ libFileNames[LIB_FILE_VERSION_TMP],
+#endif
+ objectFile,
+ pkgDataFlags[LD_SONAME],
+ pkgDataFlags[LD_SONAME][0] == 0 ? "" : libFileNames[LIB_FILE_VERSION_MAJOR],
+ pkgDataFlags[RPATH_FLAGS],
+ pkgDataFlags[BIR_FLAGS]);
+
+ /* Generate the library file. */
+ result = system(cmd);
+ }
+
+ if (freeCmd) {
+ uprv_free(cmd);
+ }
+
+ return result;
+}
+
+static int32_t pkg_createWithAssemblyCode(const char *targetDir, const char mode, const char *gencFilePath) {
+ char tempObjectFile[SMALL_BUFFER_MAX_SIZE] = "";
+ char cmd[LARGE_BUFFER_MAX_SIZE] = "";
+ int32_t result = 0;
+
+ /* Remove the ending .s and replace it with .o for the new object file. */
+ uprv_strcpy(tempObjectFile, gencFilePath);
+ tempObjectFile[uprv_strlen(tempObjectFile)-1] = 'o';
+
+ /* Generate the object file. */
+ sprintf(cmd, "%s %s -o %s %s",
+ pkgDataFlags[COMPILER],
+ pkgDataFlags[LIBFLAGS],
+ tempObjectFile,
+ gencFilePath);
+
+ result = system(cmd);
+ if (result != 0) {
+ return result;
+ }
+
+ return pkg_generateLibraryFile(targetDir, mode, tempObjectFile);
+}
+
+#ifdef BUILD_DATA_WITHOUT_ASSEMBLY
+/*
+ * Generation of the data library without assembly code needs to compile each data file
+ * individually and then link it all together.
+ */
+enum {
+ DATA_PREFIX_BRKITR,
+ DATA_PREFIX_COLL,
+ DATA_PREFIX_RBNF,
+ DATA_PREFIX_TRANSLIT,
+ DATA_PREFIX_LENGTH
+};
+const static char DATA_PREFIX[DATA_PREFIX_LENGTH][10] = {
+ "brkitr",
+ "coll",
+ "rbnf",
+ "translit"
+};
+static int32_t pkg_createWithoutAssemblyCode(UPKGOptions *o, const char *targetDir, const char mode) {
+ int32_t result = 0;
+ CharList *list = o->filePaths;
+ CharList *listNames = o->files;
+ int32_t listSize = pkg_countCharList(list);
+ char *buffer;
+ char *cmd;
+ char gencmnFile[SMALL_BUFFER_MAX_SIZE] = "";
+ char tempObjectFile[SMALL_BUFFER_MAX_SIZE] = "";
+#ifdef USE_SINGLE_CCODE_FILE
+ char icudtAll[SMALL_BUFFER_MAX_SIZE] = "";
+
+ sprintf(icudtAll, "%s%s%sall.c",
+ o->tmpDir,
+ PKGDATA_FILE_SEP_STRING,
+ libFileNames[LIB_FILE]);
+#endif
+
+ if (list == NULL || listNames == NULL) {
+ /* list and listNames should never be NULL since we are looping through the CharList with
+ * the given size.
+ */
+ return -1;
+ }
+
+ if ((cmd = (char *)uprv_malloc((listSize + 2) * SMALL_BUFFER_MAX_SIZE)) == NULL) {
+ fprintf(stderr, "Unable to allocate memory for cmd.\n");
+ return -1;
+ } else if ((buffer = (char *)uprv_malloc((listSize + 1) * SMALL_BUFFER_MAX_SIZE)) == NULL) {
+ fprintf(stderr, "Unable to allocate memory for buffer.\n");
+ uprv_free(cmd);
+ return -1;
+ }
+
+ for (int32_t i = 0; i < (listSize + 1); i++) {
+ const char *file ;
+ const char *name;
+
+ if (i == 0) {
+ /* The first iteration calls the gencmn function and initailizes the buffer. */
+ createCommonDataFile(o->tmpDir, o->shortName, o->entryName, NULL, o->srcDir, o->comment, o->fileListFiles->str, 0, TRUE, o->verbose, gencmnFile);
+ buffer[0] = 0;
+#ifdef USE_SINGLE_CCODE_FILE
+ uprv_strcpy(tempObjectFile, gencmnFile);
+ tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
+
+#ifdef OS400
+ sprintf(cmd, "QSH CMD('%s %s -o %s %s')",
+#else
+ sprintf(cmd, "%s %s -o %s %s"
+#endif
+ pkgDataFlags[COMPILER],
+ pkgDataFlags[LIBFLAGS],
+ tempObjectFile,
+ gencmnFile);
+
+ result = system(cmd);
+ if (result != 0) {
+ break;
+ }
+
+ sprintf(buffer, "%s",tempObjectFile);
+#endif
+ } else {
+ char newName[SMALL_BUFFER_MAX_SIZE];
+ char dataName[SMALL_BUFFER_MAX_SIZE];
+ const char *pSubstring;
+ file = list->str;
+ name = listNames->str;
+
+ newName[0] = dataName[0] = 0;
+ for (int32_t n = 0; n < DATA_PREFIX_LENGTH; n++) {
+ /* If the name contains a prefix, alter the new name accordingly. */
+ pSubstring = uprv_strstr(name, DATA_PREFIX[n]);
+ if (pSubstring != NULL) {
+ char newNameTmp[SMALL_BUFFER_MAX_SIZE] = "";
+ const char *p = name + uprv_strlen(DATA_PREFIX[n]) + 1;
+ for (int32_t i = 0;;i++) {
+ if (p[i] == '.') {
+ newNameTmp[i] = '_';
+ continue;
+ }
+ newNameTmp[i] = p[i];
+ if (p[i] == 0) {
+ break;
+ }
+ }
+ sprintf(newName, "%s_%s",
+ DATA_PREFIX[n],
+ newNameTmp);
+ sprintf(dataName, "%s_%s",
+ o->shortName,
+ DATA_PREFIX[n]);
+ }
+ if (newName[0] != 0) {
+ break;
+ }
+ }
+
+ writeCCode(file, o->tmpDir, dataName[0] != 0 ? dataName : o->shortName, newName[0] != 0 ? newName : NULL, gencmnFile);
+#ifdef USE_SINGLE_CCODE_FILE
+#ifdef OS400
+ sprintf(cmd, "QSH CMD('cat %s >> %s')", gencmnFile, icudtAll);
+#else
+ sprintf(cmd, "cat %s >> %s", gencmnFile, icudtAll);
+#endif
+
+ result = system(cmd);
+ if (result != 0) {
+ break;
+ }
+#endif
+ }
+
+#ifndef USE_SINGLE_CCODE_FILE
+ uprv_strcpy(tempObjectFile, gencmnFile);
+ tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
+
+ sprintf(cmd, "%s %s -o %s %s",
+ pkgDataFlags[COMPILER],
+ pkgDataFlags[LIBFLAGS],
+ tempObjectFile,
+ gencmnFile);
+ result = system(cmd);
+ if (result != 0) {
+ break;
+ }
+
+ sprintf(buffer, "%s %s",
+ buffer,
+ tempObjectFile);
+#endif
+
+ if (i > 0) {
+ list = list->next;
+ listNames = listNames->next;
+ }
+ }
+
+#ifdef USE_SINGLE_CCODE_FILE
+ uprv_strcpy(tempObjectFile, icudtAll);
+ tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
+#ifdef OS400
+ sprintf(cmd, "QSH CMD('%s %s -o %s %s')",
+#else
+ sprintf(cmd, "%s %s -o %s %s",
+#endif
+ pkgDataFlags[COMPILER],
+ pkgDataFlags[LIBFLAGS],
+ tempObjectFile,
+ icudtAll);
+
+ result = system(cmd);
+ if (result == 0) {
+ sprintf(buffer, "%s %s",
+ buffer,
+ tempObjectFile);
+ }
+#endif
+
+ if (result == 0) {
+ /* Generate the library file. */
+ result = pkg_generateLibraryFile(targetDir, mode, buffer, cmd);
+ }
+ uprv_free(buffer);
+ uprv_free(cmd);
+
+ return result;
+}
+#endif
+
+#ifdef WINDOWS_WITH_MSVC
+#define LINK_CMD "link.exe /nologo /release /out:"
+#define LINK_FLAGS "/DLL /NOENTRY /MANIFEST:NO /base:0x4ad00000 /implib:"
+#define LIB_CMD "LIB.exe /nologo /out:"
+#define LIB_FILE "icudt.lib"
+#define LIB_EXT UDATA_LIB_SUFFIX
+#define DLL_EXT UDATA_SO_SUFFIX
+
+static int32_t pkg_createWindowsDLL(const char mode, const char *gencFilePath, UPKGOptions *o) {
+ char cmd[LARGE_BUFFER_MAX_SIZE];
+ if (mode == MODE_STATIC) {
+ char staticLibFilePath[SMALL_BUFFER_MAX_SIZE] = "";
+
+ uprv_strcpy(staticLibFilePath, o->tmpDir);
+ uprv_strcat(staticLibFilePath, PKGDATA_FILE_SEP_STRING);
+
+ uprv_strcat(staticLibFilePath, o->entryName);
+ uprv_strcat(staticLibFilePath, LIB_EXT);
+
+ sprintf(cmd, "%s\"%s\" \"%s\"",
+ LIB_CMD,
+ staticLibFilePath,
+ gencFilePath);
+ } else if (mode == MODE_DLL) {
+ char dllFilePath[SMALL_BUFFER_MAX_SIZE] = "";
+ char libFilePath[SMALL_BUFFER_MAX_SIZE] = "";
+ char resFilePath[SMALL_BUFFER_MAX_SIZE] = "";
+
+#ifdef CYGWINMSVC
+ uprv_strcpy(dllFilePath, o->targetDir);
+#else
+ uprv_strcpy(dllFilePath, o->srcDir);
+#endif
+ uprv_strcat(dllFilePath, PKGDATA_FILE_SEP_STRING);
+ uprv_strcpy(libFilePath, dllFilePath);
+
+ uprv_strcpy(resFilePath, o->tmpDir);
+ uprv_strcat(resFilePath, PKGDATA_FILE_SEP_STRING);
+
+ uprv_strcat(dllFilePath, o->entryName);
+ uprv_strcat(dllFilePath, DLL_EXT);
+ uprv_strcat(libFilePath, LIB_FILE);
+ uprv_strcat(resFilePath, ICUDATA_RES_FILE);
+
+ if (!T_FileStream_file_exists(resFilePath)) {
+ uprv_memset(resFilePath, 0, sizeof(resFilePath));
+ }
+
+ /* Check if dll file and lib file exists and that it is not newer than genc file. */
+ if (!o->rebuild && (T_FileStream_file_exists(dllFilePath) && isFileModTimeLater(dllFilePath, gencFilePath)) &&
+ (T_FileStream_file_exists(libFilePath) && isFileModTimeLater(libFilePath, gencFilePath))) {
+ return 0;
+ }
+
+ sprintf(cmd, "%s\"%s\" %s\"%s\" \"%s\" \"%s\"",
+ LINK_CMD,
+ dllFilePath,
+ LINK_FLAGS,
+ libFilePath,
+ gencFilePath,
+ resFilePath
+ );
+ }
+
+ return system(cmd);
+}
+#endif
+
+static void pkg_checkFlag(UPKGOptions *o) {
+#ifdef U_AIX
+ /* AIX needs a map file. */
+ char *flag = NULL;
+ int32_t length = 0;
+ char tmpbuffer[SMALL_BUFFER_MAX_SIZE];
+ const char MAP_FILE_EXT[] = ".map";
+ FileStream *f = NULL;
+ char mapFile[SMALL_BUFFER_MAX_SIZE] = "";
+ int32_t start = -1;
+ int32_t count = 0;
+
+ flag = pkgDataFlags[BIR_FLAGS];
+ length = uprv_strlen(pkgDataFlags[BIR_FLAGS]);
+
+ for (int32_t i = 0; i < length; i++) {
+ if (flag[i] == MAP_FILE_EXT[count]) {
+ if (count == 0) {
+ start = i;
+ }
+ count++;
+ } else {
+ count = 0;
+ }
+
+ if (count == uprv_strlen(MAP_FILE_EXT)) {
+ break;
+ }
+ }
+
+ if (start >= 0) {
+ int32_t index = 0;
+ for (int32_t i = 0;;i++) {
+ if (i == start) {
+ for (int32_t n = 0;;n++) {
+ if (o->shortName[n] == 0) {
+ break;
+ }
+ tmpbuffer[index++] = o->shortName[n];
+ }
+ }
+
+ tmpbuffer[index++] = flag[i];
+
+ if (flag[i] == 0) {
+ break;
+ }
+ }
+
+ uprv_memset(flag, 0, length);
+ uprv_strcpy(flag, tmpbuffer);
+
+ uprv_strcpy(mapFile, o->shortName);
+ uprv_strcat(mapFile, MAP_FILE_EXT);
+
+ f = T_FileStream_open(mapFile, "w");
+ if (f == NULL) {
+ fprintf(stderr,"Unable to create map file: %s.\n", mapFile);
+ return;
+ }
+
+ sprintf(tmpbuffer, "%s%s ", o->entryName, UDATA_CMN_INTERMEDIATE_SUFFIX);
+
+ T_FileStream_writeLine(f, tmpbuffer);
+
+ T_FileStream_close(f);
+ }
+#elif defined(U_CYGWIN)
+ /* Cygwin needs to change flag options. */
+ char *flag = NULL;
+ int32_t length = 0;
+
+ flag = pkgDataFlags[GENLIB];
+ length = uprv_strlen(pkgDataFlags[GENLIB]);
+
+ int32_t position = length - 1;
+
+ for(;position >= 0;position--) {
+ if (flag[position] == '=') {
+ position++;
+ break;
+ }
+ }
+
+ uprv_memset(flag + position, 0, length - position);
+#elif defined(OS400)
+ /* OS400 needs to fix the ld options (swap single quote with double quote) */
+ char *flag = NULL;
+ int32_t length = 0;
+
+ flag = pkgDataFlags[GENLIB];
+ length = uprv_strlen(pkgDataFlags[GENLIB]);
+
+ int32_t position = length - 1;
+
+ for(int32_t i = 0; i < length; i++) {
+ if (flag[i] == '\'') {
+ flag[i] = '\"';
+ }
+ }
+#endif
+}
+
+static void loadLists(UPKGOptions *o, UErrorCode *status)
+{
+ CharList *l, *tail = NULL, *tail2 = NULL;
+ FileStream *in;
+ char line[16384];
+ char *linePtr, *lineNext;
+ const uint32_t lineMax = 16300;
+ char tmp[1024];
+ char *s;
+ int32_t ln=0; /* line number */
+
+ for(l = o->fileListFiles; l; l = l->next) {
+ if(o->verbose) {
+ fprintf(stdout, "# Reading %s..\n", l->str);
+ }
+ /* TODO: stdin */
+ in = T_FileStream_open(l->str, "r"); /* open files list */
+
+ if(!in) {
+ fprintf(stderr, "Error opening <%s>.\n", l->str);
+ *status = U_FILE_ACCESS_ERROR;
+ return;
+ }
+
+ while(T_FileStream_readLine(in, line, sizeof(line))!=NULL) { /* for each line */
+ ln++;
+ if(uprv_strlen(line)>lineMax) {
+ fprintf(stderr, "%s:%d - line too long (over %d chars)\n", l->str, (int)ln, (int)lineMax);
+ exit(1);
+ }
+ /* remove spaces at the beginning */
+ linePtr = line;
+ while(isspace(*linePtr)) {
+ linePtr++;
+ }
+ s=linePtr;
+ /* remove trailing newline characters */
+ while(*s!=0) {
+ if(*s=='\r' || *s=='\n') {
+ *s=0;
+ break;
+ }
+ ++s;
+ }
+ if((*linePtr == 0) || (*linePtr == '#')) {
+ continue; /* comment or empty line */
+ }
+
+ /* Now, process the line */
+ lineNext = NULL;
+
+ while(linePtr && *linePtr) { /* process space-separated items */
+ while(*linePtr == ' ') {
+ linePtr++;
+ }
+ /* Find the next quote */
+ if(linePtr[0] == '"')
+ {
+ lineNext = uprv_strchr(linePtr+1, '"');
+ if(lineNext == NULL) {
+ fprintf(stderr, "%s:%d - missing trailing double quote (\")\n",
+ l->str, (int)ln);
+ exit(1);
+ } else {
+ lineNext++;
+ if(*lineNext) {
+ if(*lineNext != ' ') {
+ fprintf(stderr, "%s:%d - malformed quoted line at position %d, expected ' ' got '%c'\n",
+ l->str, (int)ln, (int)(lineNext-line), (*lineNext)?*lineNext:'0');
+ exit(1);
+ }
+ *lineNext = 0;
+ lineNext++;
+ }
+ }
+ } else {
+ lineNext = uprv_strchr(linePtr, ' ');
+ if(lineNext) {
+ *lineNext = 0; /* terminate at space */
+ lineNext++;
+ }
+ }
+
+ /* add the file */
+ s = (char*)getLongPathname(linePtr);
+
+ /* normal mode.. o->files is just the bare list without package names */
+ o->files = pkg_appendToList(o->files, &tail, uprv_strdup(linePtr));
+ if(uprv_pathIsAbsolute(s)) {
+ fprintf(stderr, "pkgdata: Error: absolute path encountered. Old style paths are not supported. Use relative paths such as 'fur.res' or 'translit%cfur.res'.\n\tBad path: '%s'\n", U_FILE_SEP_CHAR, s);
+ exit(U_ILLEGAL_ARGUMENT_ERROR);
+ }
+ uprv_strcpy(tmp, o->srcDir);
+ uprv_strcat(tmp, o->srcDir[uprv_strlen(o->srcDir)-1] == U_FILE_SEP_CHAR ? "" :PKGDATA_FILE_SEP_STRING);
+ uprv_strcat(tmp, s);
+ o->filePaths = pkg_appendToList(o->filePaths, &tail2, uprv_strdup(tmp));
+ linePtr = lineNext;
+ } /* for each entry on line */
+ } /* for each line */
+ T_FileStream_close(in);
+ } /* for each file list file */
+}
+
+/* Try calling icu-config directly to get the option file. */
+static int32_t pkg_getOptionsFromICUConfig(UOption *option) {
+#if U_HAVE_POPEN
+ FILE *p;
+ size_t n;
+ static char buf[512] = "";
+ const char cmd[] = "icu-config --incpkgdatafile";
+
+ p = popen(cmd, "r");
+
+ if(p == NULL)
+ {
+ fprintf(stderr, "%s: icu-config: No icu-config found. (fix PATH or use -O option)\n", progname);
+ return -1;
+ }
+
+ n = fread(buf, 1, 511, p);
+
+ pclose(p);
+
+ if(n<=0)
+ {
+ fprintf(stderr,"%s: icu-config: Could not read from icu-config. (fix PATH or use -O option)\n", progname);
+ return -1;
+ }
+
+ for (int32_t length = strlen(buf) - 1; length >= 0; length--) {
+ if (buf[length] == '\n' || buf[length] == ' ') {
+ buf[length] = 0;
+ } else {
+ break;
+ }
+ }
+
+ if(buf[strlen(buf)-1]=='\n')
+ {
+ buf[strlen(buf)-1]=0;
+ }
+
+ if(buf[0] == 0)
+ {
+ fprintf(stderr, "%s: icu-config: invalid response from icu-config (fix PATH or use -O option)\n", progname);
+ return -1;
+ }
+
+ option->value = buf;
+ option->doesOccur = TRUE;
+
+ return 0;
+#endif
+ return -1;
+}
Modified: trunk/source/tools/toolutil/pkg_genc.c
===================================================================
--- trunk/source/tools/toolutil/pkg_genc.c 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/tools/toolutil/pkg_genc.c 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,1162 +1,1162 @@
-/******************************************************************************
- * Copyright (C) 2009, International Business Machines
- * Corporation and others. All Rights Reserved.
- *******************************************************************************
- */
-#include "unicode/utypes.h"
-
-#ifdef U_WINDOWS
-# define VC_EXTRALEAN
-# define WIN32_LEAN_AND_MEAN
-# define NOUSER
-# define NOSERVICE
-# define NOIME
-# define NOMCX
-#include <windows.h>
-#include <time.h>
-# ifdef __GNUC__
-# define WINDOWS_WITH_GNUC
-# endif
-#endif
-
-#ifdef U_LINUX
-# define U_ELF
-#endif
-
-#ifdef U_ELF
-# include <elf.h>
-# if defined(ELFCLASS64)
-# define U_ELF64
-# endif
- /* Old elf.h headers may not have EM_X86_64, or have EM_X8664 instead. */
-# ifndef EM_X86_64
-# define EM_X86_64 62
-# endif
-# define ICU_ENTRY_OFFSET 0
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "unicode/putil.h"
-#include "cmemory.h"
-#include "cstring.h"
-#include "filestrm.h"
-#include "toolutil.h"
-#include "unicode/uclean.h"
-#include "uoptions.h"
-#include "pkg_genc.h"
-
-#define MAX_COLUMN ((uint32_t)(0xFFFFFFFFU))
-
-#define HEX_0X 0 /* 0x1234 */
-#define HEX_0H 1 /* 01234h */
-
-#if defined(U_WINDOWS) || defined(U_ELF)
-#define CAN_GENERATE_OBJECTS
-#endif
-
-/* prototypes --------------------------------------------------------------- */
-static void
-getOutFilename(const char *inFilename, const char *destdir, char *outFilename, char *entryName, const char *newSuffix, const char *optFilename);
-
-static uint32_t
-write8(FileStream *out, uint8_t byte, uint32_t column);
-
-static uint32_t
-write32(FileStream *out, uint32_t byte, uint32_t column);
-
-#ifdef OS400
-static uint32_t
-write8str(FileStream *out, uint8_t byte, uint32_t column);
-#endif
-/* -------------------------------------------------------------------------- */
-
-/*
-Creating Template Files for New Platforms
-
-Let the cc compiler help you get started.
-Compile this program
- const unsigned int x[5] = {1, 2, 0xdeadbeef, 0xffffffff, 16};
-with the -S option to produce assembly output.
-
-For example, this will generate array.s:
-gcc -S array.c
-
-This will produce a .s file that may look like this:
-
- .file "array.c"
- .version "01.01"
-gcc2_compiled.:
- .globl x
- .section .rodata
- .align 4
- .type x, at object
- .size x,20
-x:
- .long 1
- .long 2
- .long -559038737
- .long -1
- .long 16
- .ident "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.1 2.96-85)"
-
-which gives a starting point that will compile, and can be transformed
-to become the template, generally with some consulting of as docs and
-some experimentation.
-
-If you want ICU to automatically use this assembly, you should
-specify "GENCCODE_ASSEMBLY=-a name" in the specific config/mh-* file,
-where the name is the compiler or platform that you used in this
-assemblyHeader data structure.
-*/
-static const struct AssemblyType {
- const char *name;
- const char *header;
- const char *beginLine;
- const char *footer;
- int8_t hexType; /* HEX_0X or HEX_0h */
-} assemblyHeader[] = {
- {"gcc",
- ".globl %s\n"
- "\t.section .note.GNU-stack,\"\", at progbits\n"
- "\t.section .rodata\n"
- "\t.align 8\n" /* Either align 8 bytes or 2^8 (256) bytes. 8 bytes is needed. */
- "\t.type %s, at object\n"
- "%s:\n\n",
-
- ".long ","",HEX_0X
- },
- {"gcc-darwin",
- /*"\t.section __TEXT,__text,regular,pure_instructions\n"
- "\t.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32\n"*/
- ".globl _%s\n"
- "\t.data\n"
- "\t.const\n"
- "\t.align 4\n" /* 1<<4 = 16 */
- "_%s:\n\n",
-
- ".long ","",HEX_0X
- },
- {"gcc-cygwin",
- ".globl _%s\n"
- "\t.section .rodata\n"
- "\t.align 8\n" /* Either align 8 bytes or 2^8 (256) bytes. 8 bytes is needed. */
- "_%s:\n\n",
-
- ".long ","",HEX_0X
- },
- {"sun",
- "\t.section \".rodata\"\n"
- "\t.align 8\n"
- ".globl %s\n"
- "%s:\n",
-
- ".word ","",HEX_0X
- },
- {"sun-x86",
- "Drodata.rodata:\n"
- "\t.type Drodata.rodata, at object\n"
- "\t.size Drodata.rodata,0\n"
- "\t.globl %s\n"
- "\t.align 8\n"
- "%s:\n",
-
- ".4byte ","",HEX_0X
- },
- {"xlc",
- ".globl %s{RO}\n"
- "\t.toc\n"
- "%s:\n"
- "\t.csect %s{RO}, 4\n",
-
- ".long ","",HEX_0X
- },
- {"aCC-ia64",
- "\t.file \"%s.s\"\n"
- "\t.type %s, at object\n"
- "\t.global %s\n"
- "\t.secalias .abe$0.rodata, \".rodata\"\n"
- "\t.section .abe$0.rodata = \"a\", \"progbits\"\n"
- "\t.align 16\n"
- "%s::\t",
-
- "data4 ","",HEX_0X
- },
- {"aCC-parisc",
- "\t.SPACE $TEXT$\n"
- "\t.SUBSPA $LIT$\n"
- "%s\n"
- "\t.EXPORT %s\n"
- "\t.ALIGN 16\n",
-
- ".WORD ","",HEX_0X
- },
- { "masm",
- "\tTITLE %s\n"
- "; generated by genccode\n"
- ".386\n"
- ".model flat\n"
- "\tPUBLIC _%s\n"
- "ICUDATA_%s\tSEGMENT READONLY PARA PUBLIC FLAT 'DATA'\n"
- "\tALIGN 16\n"
- "_%s\tLABEL DWORD\n",
- "\tDWORD ","\nICUDATA_%s\tENDS\n\tEND\n",HEX_0H
- }
-};
-
-static int32_t assemblyHeaderIndex = -1;
-static int32_t hexType = HEX_0X;
-
-U_CAPI UBool U_EXPORT2
-checkAssemblyHeaderName(const char* optAssembly) {
- int32_t idx;
- assemblyHeaderIndex = -1;
- for (idx = 0; idx < (int32_t)(sizeof(assemblyHeader)/sizeof(assemblyHeader[0])); idx++) {
- if (uprv_strcmp(optAssembly, assemblyHeader[idx].name) == 0) {
- assemblyHeaderIndex = idx;
- hexType = assemblyHeader[idx].hexType; /* set the hex type */
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-
-U_CAPI void U_EXPORT2
-printAssemblyHeadersToStdErr(void) {
- int32_t idx;
- fprintf(stderr, "%s", assemblyHeader[0].name);
- for (idx = 1; idx < (int32_t)(sizeof(assemblyHeader)/sizeof(assemblyHeader[0])); idx++) {
- fprintf(stderr, ", %s", assemblyHeader[idx].name);
- }
- fprintf(stderr,
- ")\n");
-}
-
-U_CAPI void U_EXPORT2
-writeAssemblyCode(const char *filename, const char *destdir, const char *optEntryPoint, const char *optFilename, char *outFilePath) {
- uint32_t column = MAX_COLUMN;
- char entry[64];
- uint32_t buffer[1024];
- char *bufferStr = (char *)buffer;
- FileStream *in, *out;
- size_t i, length;
-
- in=T_FileStream_open(filename, "rb");
- if(in==NULL) {
- fprintf(stderr, "genccode: unable to open input file %s\n", filename);
- exit(U_FILE_ACCESS_ERROR);
- }
-
- getOutFilename(filename, destdir, bufferStr, entry, ".s", optFilename);
- out=T_FileStream_open(bufferStr, "w");
- if(out==NULL) {
- fprintf(stderr, "genccode: unable to open output file %s\n", bufferStr);
- exit(U_FILE_ACCESS_ERROR);
- }
-
- if (outFilePath != NULL) {
- uprv_strcpy(outFilePath, bufferStr);
- }
-
-#ifdef WINDOWS_WITH_GNUC
- /* Need to fix the file seperator character when using MinGW. */
- swapFileSepChar(outFilePath, U_FILE_SEP_CHAR, '/');
-#endif
-
- if(optEntryPoint != NULL) {
- uprv_strcpy(entry, optEntryPoint);
- uprv_strcat(entry, "_dat");
- }
-
- /* turn dashes or dots in the entry name into underscores */
- length=uprv_strlen(entry);
- for(i=0; i<length; ++i) {
- if(entry[i]=='-' || entry[i]=='.') {
- entry[i]='_';
- }
- }
-
- sprintf(bufferStr, assemblyHeader[assemblyHeaderIndex].header,
- entry, entry, entry, entry,
- entry, entry, entry, entry);
- T_FileStream_writeLine(out, bufferStr);
- T_FileStream_writeLine(out, assemblyHeader[assemblyHeaderIndex].beginLine);
-
- for(;;) {
- length=T_FileStream_read(in, buffer, sizeof(buffer));
- if(length==0) {
- break;
- }
- if (length != sizeof(buffer)) {
- /* pad with extra 0's when at the end of the file */
- for(i=0; i < (length % sizeof(uint32_t)); ++i) {
- buffer[length+i] = 0;
- }
- }
- for(i=0; i<(length/sizeof(buffer[0])); i++) {
- column = write32(out, buffer[i], column);
- }
- }
-
- T_FileStream_writeLine(out, "\n");
-
- sprintf(bufferStr, assemblyHeader[assemblyHeaderIndex].footer,
- entry, entry, entry, entry,
- entry, entry, entry, entry);
- T_FileStream_writeLine(out, bufferStr);
-
- if(T_FileStream_error(in)) {
- fprintf(stderr, "genccode: file read error while generating from file %s\n", filename);
- exit(U_FILE_ACCESS_ERROR);
- }
-
- if(T_FileStream_error(out)) {
- fprintf(stderr, "genccode: file write error while generating from file %s\n", filename);
- exit(U_FILE_ACCESS_ERROR);
- }
-
- T_FileStream_close(out);
- T_FileStream_close(in);
-}
-
-U_CAPI void U_EXPORT2
-writeCCode(const char *filename, const char *destdir, const char *optName, const char *optFilename, char *outFilePath) {
- uint32_t column = MAX_COLUMN;
- char buffer[4096], entry[64];
- FileStream *in, *out;
- size_t i, length;
-
- in=T_FileStream_open(filename, "rb");
- if(in==NULL) {
- fprintf(stderr, "genccode: unable to open input file %s\n", filename);
- exit(U_FILE_ACCESS_ERROR);
- }
-
- if(optName != NULL) { /* prepend 'icudt28_' */
- strcpy(entry, optName);
- strcat(entry, "_");
- } else {
- entry[0] = 0;
- }
-
- getOutFilename(filename, destdir, buffer, entry+uprv_strlen(entry), ".c", optFilename);
- if (outFilePath != NULL) {
- uprv_strcpy(outFilePath, buffer);
- }
- out=T_FileStream_open(buffer, "w");
- if(out==NULL) {
- fprintf(stderr, "genccode: unable to open output file %s\n", buffer);
- exit(U_FILE_ACCESS_ERROR);
- }
-
- /* turn dashes or dots in the entry name into underscores */
- length=uprv_strlen(entry);
- for(i=0; i<length; ++i) {
- if(entry[i]=='-' || entry[i]=='.') {
- entry[i]='_';
- }
- }
-
-#ifdef OS400
- /*
- TODO: Fix this once the compiler implements this feature. Keep in sync with udatamem.c
-
- This is here because this platform can't currently put
- const data into the read-only pages of an object or
- shared library (service program). Only strings are allowed in read-only
- pages, so we use char * strings to store the data.
-
- In order to prevent the beginning of the data from ever matching the
- magic numbers we must still use the initial double.
- [grhoten 4/24/2003]
- */
- sprintf(buffer,
- "#define U_DISABLE_RENAMING 1\n"
- "#include \"unicode/umachine.h\"\n"
- "U_CDECL_BEGIN\n"
- "const struct {\n"
- " double bogus;\n"
- " const char *bytes; \n"
- "} %s={ 0.0, \n",
- entry);
- T_FileStream_writeLine(out, buffer);
-
- for(;;) {
- length=T_FileStream_read(in, buffer, sizeof(buffer));
- if(length==0) {
- break;
- }
- for(i=0; i<length; ++i) {
- column = write8str(out, (uint8_t)buffer[i], column);
- }
- }
-
- T_FileStream_writeLine(out, "\"\n};\nU_CDECL_END\n");
-#else
- /* Function renaming shouldn't be done in data */
- sprintf(buffer,
- "#define U_DISABLE_RENAMING 1\n"
- "#include \"unicode/umachine.h\"\n"
- "U_CDECL_BEGIN\n"
- "const struct {\n"
- " double bogus;\n"
- " uint8_t bytes[%ld]; \n"
- "} %s={ 0.0, {\n",
- (long)T_FileStream_size(in), entry);
- T_FileStream_writeLine(out, buffer);
-
- for(;;) {
- length=T_FileStream_read(in, buffer, sizeof(buffer));
- if(length==0) {
- break;
- }
- for(i=0; i<length; ++i) {
- column = write8(out, (uint8_t)buffer[i], column);
- }
- }
-
- T_FileStream_writeLine(out, "\n}\n};\nU_CDECL_END\n");
-#endif
-
- if(T_FileStream_error(in)) {
- fprintf(stderr, "genccode: file read error while generating from file %s\n", filename);
- exit(U_FILE_ACCESS_ERROR);
- }
-
- if(T_FileStream_error(out)) {
- fprintf(stderr, "genccode: file write error while generating from file %s\n", filename);
- exit(U_FILE_ACCESS_ERROR);
- }
-
- T_FileStream_close(out);
- T_FileStream_close(in);
-}
-
-static uint32_t
-write32(FileStream *out, uint32_t bitField, uint32_t column) {
- int32_t i;
- char bitFieldStr[64]; /* This is more bits than needed for a 32-bit number */
- char *s = bitFieldStr;
- uint8_t *ptrIdx = (uint8_t *)&bitField;
- static const char hexToStr[16] = {
- '0','1','2','3',
- '4','5','6','7',
- '8','9','A','B',
- 'C','D','E','F'
- };
-
- /* write the value, possibly with comma and newline */
- if(column==MAX_COLUMN) {
- /* first byte */
- column=1;
- } else if(column<32) {
- *(s++)=',';
- ++column;
- } else {
- *(s++)='\n';
- uprv_strcpy(s, assemblyHeader[assemblyHeaderIndex].beginLine);
- s+=uprv_strlen(s);
- column=1;
- }
-
- if (bitField < 10) {
- /* It's a small number. Don't waste the space for 0x */
- *(s++)=hexToStr[bitField];
- }
- else {
- int seenNonZero = 0; /* This is used to remove leading zeros */
-
- if(hexType==HEX_0X) {
- *(s++)='0';
- *(s++)='x';
- } else if(hexType==HEX_0H) {
- *(s++)='0';
- }
-
- /* This creates a 32-bit field */
-#if U_IS_BIG_ENDIAN
- for (i = 0; i < sizeof(uint32_t); i++)
-#else
- for (i = sizeof(uint32_t)-1; i >= 0 ; i--)
-#endif
- {
- uint8_t value = ptrIdx[i];
- if (value || seenNonZero) {
- *(s++)=hexToStr[value>>4];
- *(s++)=hexToStr[value&0xF];
- seenNonZero = 1;
- }
- }
- if(hexType==HEX_0H) {
- *(s++)='h';
- }
- }
-
- *(s++)=0;
- T_FileStream_writeLine(out, bitFieldStr);
- return column;
-}
-
-static uint32_t
-write8(FileStream *out, uint8_t byte, uint32_t column) {
- char s[4];
- int i=0;
-
- /* convert the byte value to a string */
- if(byte>=100) {
- s[i++]=(char)('0'+byte/100);
- byte%=100;
- }
- if(i>0 || byte>=10) {
- s[i++]=(char)('0'+byte/10);
- byte%=10;
- }
- s[i++]=(char)('0'+byte);
- s[i]=0;
-
- /* write the value, possibly with comma and newline */
- if(column==MAX_COLUMN) {
- /* first byte */
- column=1;
- } else if(column<16) {
- T_FileStream_writeLine(out, ",");
- ++column;
- } else {
- T_FileStream_writeLine(out, ",\n");
- column=1;
- }
- T_FileStream_writeLine(out, s);
- return column;
-}
-
-#ifdef OS400
-static uint32_t
-write8str(FileStream *out, uint8_t byte, uint32_t column) {
- char s[8];
-
- if (byte > 7)
- sprintf(s, "\\x%X", byte);
- else
- sprintf(s, "\\%X", byte);
-
- /* write the value, possibly with comma and newline */
- if(column==MAX_COLUMN) {
- /* first byte */
- column=1;
- T_FileStream_writeLine(out, "\"");
- } else if(column<24) {
- ++column;
- } else {
- T_FileStream_writeLine(out, "\"\n\"");
- column=1;
- }
- T_FileStream_writeLine(out, s);
- return column;
-}
-#endif
-
-static void
-getOutFilename(const char *inFilename, const char *destdir, char *outFilename, char *entryName, const char *newSuffix, const char *optFilename) {
- const char *basename=findBasename(inFilename), *suffix=uprv_strrchr(basename, '.');
-
- /* copy path */
- if(destdir!=NULL && *destdir!=0) {
- do {
- *outFilename++=*destdir++;
- } while(*destdir!=0);
- if(*(outFilename-1)!=U_FILE_SEP_CHAR) {
- *outFilename++=U_FILE_SEP_CHAR;
- }
- inFilename=basename;
- } else {
- while(inFilename<basename) {
- *outFilename++=*inFilename++;
- }
- }
-
- if(suffix==NULL) {
- /* the filename does not have a suffix */
- uprv_strcpy(entryName, inFilename);
- if(optFilename != NULL) {
- uprv_strcpy(outFilename, optFilename);
- } else {
- uprv_strcpy(outFilename, inFilename);
- }
- uprv_strcat(outFilename, newSuffix);
- } else {
- char *saveOutFilename = outFilename;
- /* copy basename */
- while(inFilename<suffix) {
- if(*inFilename=='-') {
- /* iSeries cannot have '-' in the .o objects. */
- *outFilename++=*entryName++='_';
- inFilename++;
- }
- else {
- *outFilename++=*entryName++=*inFilename++;
- }
- }
-
- /* replace '.' by '_' */
- *outFilename++=*entryName++='_';
- ++inFilename;
-
- /* copy suffix */
- while(*inFilename!=0) {
- *outFilename++=*entryName++=*inFilename++;
- }
-
- *entryName=0;
-
- if(optFilename != NULL) {
- uprv_strcpy(saveOutFilename, optFilename);
- uprv_strcat(saveOutFilename, newSuffix);
- } else {
- /* add ".c" */
- uprv_strcpy(outFilename, newSuffix);
- }
- }
-}
-
-#ifdef CAN_GENERATE_OBJECTS
-static void
-getArchitecture(uint16_t *pCPU, uint16_t *pBits, UBool *pIsBigEndian, const char *optMatchArch) {
- int64_t buffer[256];
- const char *filename;
- FileStream *in;
- int32_t length;
-
-#ifdef U_ELF
- /* Pointer to ELF header. Elf32_Ehdr and ELF64_Ehdr are identical for the necessary fields. */
- const Elf32_Ehdr *pHeader32;
-#elif defined(U_WINDOWS)
- const IMAGE_FILE_HEADER *pHeader;
-#else
-# error "Unknown platform for CAN_GENERATE_OBJECTS."
-#endif
-
- if(optMatchArch != NULL) {
- filename=optMatchArch;
- } else {
- /* set defaults */
-#ifdef U_ELF
- /* set EM_386 because elf.h does not provide better defaults */
- *pCPU=EM_386;
- *pBits=32;
- *pIsBigEndian=(UBool)(U_IS_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB);
-#elif defined(U_WINDOWS)
-/* _M_IA64 should be defined in windows.h */
-# if defined(_M_IA64)
- *pCPU=IMAGE_FILE_MACHINE_IA64;
-# elif defined(_M_AMD64)
- *pCPU=IMAGE_FILE_MACHINE_AMD64;
-# else
- *pCPU=IMAGE_FILE_MACHINE_I386;
-# endif
- *pBits= *pCPU==IMAGE_FILE_MACHINE_I386 ? 32 : 64;
- *pIsBigEndian=FALSE;
-#else
-# error "Unknown platform for CAN_GENERATE_OBJECTS."
-#endif
- return;
- }
-
- in=T_FileStream_open(filename, "rb");
- if(in==NULL) {
- fprintf(stderr, "genccode: unable to open match-arch file %s\n", filename);
- exit(U_FILE_ACCESS_ERROR);
- }
- length=T_FileStream_read(in, buffer, sizeof(buffer));
-
-#ifdef U_ELF
- if(length<sizeof(Elf32_Ehdr)) {
- fprintf(stderr, "genccode: match-arch file %s is too short\n", filename);
- exit(U_UNSUPPORTED_ERROR);
- }
- pHeader32=(const Elf32_Ehdr *)buffer;
- if(
- pHeader32->e_ident[0]!=ELFMAG0 ||
- pHeader32->e_ident[1]!=ELFMAG1 ||
- pHeader32->e_ident[2]!=ELFMAG2 ||
- pHeader32->e_ident[3]!=ELFMAG3 ||
- pHeader32->e_ident[EI_CLASS]<ELFCLASS32 || pHeader32->e_ident[EI_CLASS]>ELFCLASS64
- ) {
- fprintf(stderr, "genccode: match-arch file %s is not an ELF object file, or not supported\n", filename);
- exit(U_UNSUPPORTED_ERROR);
- }
-
- *pBits= pHeader32->e_ident[EI_CLASS]==ELFCLASS32 ? 32 : 64; /* only 32 or 64: see check above */
-#ifdef U_ELF64
- if(*pBits!=32 && *pBits!=64) {
- fprintf(stderr, "genccode: currently only supports 32-bit and 64-bit ELF format\n");
- exit(U_UNSUPPORTED_ERROR);
- }
-#else
- if(*pBits!=32) {
- fprintf(stderr, "genccode: built with elf.h missing 64-bit definitions\n");
- exit(U_UNSUPPORTED_ERROR);
- }
-#endif
-
- *pIsBigEndian=(UBool)(pHeader32->e_ident[EI_DATA]==ELFDATA2MSB);
- if(*pIsBigEndian!=U_IS_BIG_ENDIAN) {
- fprintf(stderr, "genccode: currently only same-endianness ELF formats are supported\n");
- exit(U_UNSUPPORTED_ERROR);
- }
- /* TODO: Support byte swapping */
-
- *pCPU=pHeader32->e_machine;
-#elif defined(U_WINDOWS)
- if(length<sizeof(IMAGE_FILE_HEADER)) {
- fprintf(stderr, "genccode: match-arch file %s is too short\n", filename);
- exit(U_UNSUPPORTED_ERROR);
- }
- pHeader=(const IMAGE_FILE_HEADER *)buffer;
- *pCPU=pHeader->Machine;
- /*
- * The number of bits is implicit with the Machine value.
- * *pBits is ignored in the calling code, so this need not be precise.
- */
- *pBits= *pCPU==IMAGE_FILE_MACHINE_I386 ? 32 : 64;
- /* Windows always runs on little-endian CPUs. */
- *pIsBigEndian=FALSE;
-#else
-# error "Unknown platform for CAN_GENERATE_OBJECTS."
-#endif
-
- T_FileStream_close(in);
-}
-
-U_CAPI void U_EXPORT2
-writeObjectCode(const char *filename, const char *destdir, const char *optEntryPoint, const char *optMatchArch, const char *optFilename, char *outFilePath) {
- /* common variables */
- char buffer[4096], entry[40]={ 0 };
- FileStream *in, *out;
- const char *newSuffix;
- int32_t i, entryLength, length, size, entryOffset=0, entryLengthOffset=0;
-
- uint16_t cpu, bits;
- UBool makeBigEndian;
-
- /* platform-specific variables and initialization code */
-#ifdef U_ELF
- /* 32-bit Elf file header */
- static Elf32_Ehdr header32={
- {
- /* e_ident[] */
- ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
- ELFCLASS32,
- U_IS_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB,
- EV_CURRENT /* EI_VERSION */
- },
- ET_REL,
- EM_386,
- EV_CURRENT, /* e_version */
- 0, /* e_entry */
- 0, /* e_phoff */
- (Elf32_Off)sizeof(Elf32_Ehdr), /* e_shoff */
- 0, /* e_flags */
- (Elf32_Half)sizeof(Elf32_Ehdr), /* eh_size */
- 0, /* e_phentsize */
- 0, /* e_phnum */
- (Elf32_Half)sizeof(Elf32_Shdr), /* e_shentsize */
- 5, /* e_shnum */
- 2 /* e_shstrndx */
- };
-
- /* 32-bit Elf section header table */
- static Elf32_Shdr sectionHeaders32[5]={
- { /* SHN_UNDEF */
- 0
- },
- { /* .symtab */
- 1, /* sh_name */
- SHT_SYMTAB,
- 0, /* sh_flags */
- 0, /* sh_addr */
- (Elf32_Off)(sizeof(header32)+sizeof(sectionHeaders32)), /* sh_offset */
- (Elf32_Word)(2*sizeof(Elf32_Sym)), /* sh_size */
- 3, /* sh_link=sect hdr index of .strtab */
- 1, /* sh_info=One greater than the symbol table index of the last
- * local symbol (with STB_LOCAL). */
- 4, /* sh_addralign */
- (Elf32_Word)(sizeof(Elf32_Sym)) /* sh_entsize */
- },
- { /* .shstrtab */
- 9, /* sh_name */
- SHT_STRTAB,
- 0, /* sh_flags */
- 0, /* sh_addr */
- (Elf32_Off)(sizeof(header32)+sizeof(sectionHeaders32)+2*sizeof(Elf32_Sym)), /* sh_offset */
- 40, /* sh_size */
- 0, /* sh_link */
- 0, /* sh_info */
- 1, /* sh_addralign */
- 0 /* sh_entsize */
- },
- { /* .strtab */
- 19, /* sh_name */
- SHT_STRTAB,
- 0, /* sh_flags */
- 0, /* sh_addr */
- (Elf32_Off)(sizeof(header32)+sizeof(sectionHeaders32)+2*sizeof(Elf32_Sym)+40), /* sh_offset */
- (Elf32_Word)sizeof(entry), /* sh_size */
- 0, /* sh_link */
- 0, /* sh_info */
- 1, /* sh_addralign */
- 0 /* sh_entsize */
- },
- { /* .rodata */
- 27, /* sh_name */
- SHT_PROGBITS,
- SHF_ALLOC, /* sh_flags */
- 0, /* sh_addr */
- (Elf32_Off)(sizeof(header32)+sizeof(sectionHeaders32)+2*sizeof(Elf32_Sym)+40+sizeof(entry)), /* sh_offset */
- 0, /* sh_size */
- 0, /* sh_link */
- 0, /* sh_info */
- 16, /* sh_addralign */
- 0 /* sh_entsize */
- }
- };
-
- /* symbol table */
- static Elf32_Sym symbols32[2]={
- { /* STN_UNDEF */
- 0
- },
- { /* data entry point */
- 1, /* st_name */
- 0, /* st_value */
- 0, /* st_size */
- ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT),
- 0, /* st_other */
- 4 /* st_shndx=index of related section table entry */
- }
- };
-
- /* section header string table, with decimal string offsets */
- static const char sectionStrings[40]=
- /* 0 */ "\0"
- /* 1 */ ".symtab\0"
- /* 9 */ ".shstrtab\0"
- /* 19 */ ".strtab\0"
- /* 27 */ ".rodata\0"
- /* 35 */ "\0\0\0\0"; /* contains terminating NUL */
- /* 40: padded to multiple of 8 bytes */
-
- /*
- * Use entry[] for the string table which will contain only the
- * entry point name.
- * entry[0] must be 0 (NUL)
- * The entry point name can be up to 38 characters long (sizeof(entry)-2).
- */
-
- /* 16-align .rodata in the .o file, just in case */
- static const char padding[16]={ 0 };
- int32_t paddingSize;
-
-#ifdef U_ELF64
- /* 64-bit Elf file header */
- static Elf64_Ehdr header64={
- {
- /* e_ident[] */
- ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
- ELFCLASS64,
- U_IS_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB,
- EV_CURRENT /* EI_VERSION */
- },
- ET_REL,
- EM_X86_64,
- EV_CURRENT, /* e_version */
- 0, /* e_entry */
- 0, /* e_phoff */
- (Elf64_Off)sizeof(Elf64_Ehdr), /* e_shoff */
- 0, /* e_flags */
- (Elf64_Half)sizeof(Elf64_Ehdr), /* eh_size */
- 0, /* e_phentsize */
- 0, /* e_phnum */
- (Elf64_Half)sizeof(Elf64_Shdr), /* e_shentsize */
- 5, /* e_shnum */
- 2 /* e_shstrndx */
- };
-
- /* 64-bit Elf section header table */
- static Elf64_Shdr sectionHeaders64[5]={
- { /* SHN_UNDEF */
- 0
- },
- { /* .symtab */
- 1, /* sh_name */
- SHT_SYMTAB,
- 0, /* sh_flags */
- 0, /* sh_addr */
- (Elf64_Off)(sizeof(header64)+sizeof(sectionHeaders64)), /* sh_offset */
- (Elf64_Xword)(2*sizeof(Elf64_Sym)), /* sh_size */
- 3, /* sh_link=sect hdr index of .strtab */
- 1, /* sh_info=One greater than the symbol table index of the last
- * local symbol (with STB_LOCAL). */
- 4, /* sh_addralign */
- (Elf64_Xword)(sizeof(Elf64_Sym)) /* sh_entsize */
- },
- { /* .shstrtab */
- 9, /* sh_name */
- SHT_STRTAB,
- 0, /* sh_flags */
- 0, /* sh_addr */
- (Elf64_Off)(sizeof(header64)+sizeof(sectionHeaders64)+2*sizeof(Elf64_Sym)), /* sh_offset */
- 40, /* sh_size */
- 0, /* sh_link */
- 0, /* sh_info */
- 1, /* sh_addralign */
- 0 /* sh_entsize */
- },
- { /* .strtab */
- 19, /* sh_name */
- SHT_STRTAB,
- 0, /* sh_flags */
- 0, /* sh_addr */
- (Elf64_Off)(sizeof(header64)+sizeof(sectionHeaders64)+2*sizeof(Elf64_Sym)+40), /* sh_offset */
- (Elf64_Xword)sizeof(entry), /* sh_size */
- 0, /* sh_link */
- 0, /* sh_info */
- 1, /* sh_addralign */
- 0 /* sh_entsize */
- },
- { /* .rodata */
- 27, /* sh_name */
- SHT_PROGBITS,
- SHF_ALLOC, /* sh_flags */
- 0, /* sh_addr */
- (Elf64_Off)(sizeof(header64)+sizeof(sectionHeaders64)+2*sizeof(Elf64_Sym)+40+sizeof(entry)), /* sh_offset */
- 0, /* sh_size */
- 0, /* sh_link */
- 0, /* sh_info */
- 16, /* sh_addralign */
- 0 /* sh_entsize */
- }
- };
-
- /*
- * 64-bit symbol table
- * careful: different order of items compared with Elf32_sym!
- */
- static Elf64_Sym symbols64[2]={
- { /* STN_UNDEF */
- 0
- },
- { /* data entry point */
- 1, /* st_name */
- ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT),
- 0, /* st_other */
- 4, /* st_shndx=index of related section table entry */
- 0, /* st_value */
- 0 /* st_size */
- }
- };
-
-#endif /* U_ELF64 */
-
- /* entry[] have a leading NUL */
- entryOffset=1;
-
- /* in the common code, count entryLength from after the NUL */
- entryLengthOffset=1;
-
- newSuffix=".o";
-
-#elif defined(U_WINDOWS)
- struct {
- IMAGE_FILE_HEADER fileHeader;
- IMAGE_SECTION_HEADER sections[2];
- char linkerOptions[100];
- } objHeader;
- IMAGE_SYMBOL symbols[1];
- struct {
- DWORD sizeofLongNames;
- char longNames[100];
- } symbolNames;
-
- /*
- * entry sometimes have a leading '_'
- * overwritten if entryOffset==0 depending on the target platform
- * see check for cpu below
- */
- entry[0]='_';
-
- newSuffix=".obj";
-#else
-# error "Unknown platform for CAN_GENERATE_OBJECTS."
-#endif
-
- /* deal with options, files and the entry point name */
- getArchitecture(&cpu, &bits, &makeBigEndian, optMatchArch);
- printf("genccode: --match-arch cpu=%hu bits=%hu big-endian=%hu\n", cpu, bits, makeBigEndian);
-#ifdef U_WINDOWS
- if(cpu==IMAGE_FILE_MACHINE_I386) {
- entryOffset=1;
- }
-#endif
-
- in=T_FileStream_open(filename, "rb");
- if(in==NULL) {
- fprintf(stderr, "genccode: unable to open input file %s\n", filename);
- exit(U_FILE_ACCESS_ERROR);
- }
- size=T_FileStream_size(in);
-
- getOutFilename(filename, destdir, buffer, entry+entryOffset, newSuffix, optFilename);
- if (outFilePath != NULL) {
- uprv_strcpy(outFilePath, buffer);
- }
-
- if(optEntryPoint != NULL) {
- uprv_strcpy(entry+entryOffset, optEntryPoint);
- uprv_strcat(entry+entryOffset, "_dat");
- }
- /* turn dashes in the entry name into underscores */
- entryLength=(int32_t)uprv_strlen(entry+entryLengthOffset);
- for(i=0; i<entryLength; ++i) {
- if(entry[entryLengthOffset+i]=='-') {
- entry[entryLengthOffset+i]='_';
- }
- }
-
- /* open the output file */
- out=T_FileStream_open(buffer, "wb");
- if(out==NULL) {
- fprintf(stderr, "genccode: unable to open output file %s\n", buffer);
- exit(U_FILE_ACCESS_ERROR);
- }
-
-#ifdef U_ELF
- if(bits==32) {
- header32.e_ident[EI_DATA]= makeBigEndian ? ELFDATA2MSB : ELFDATA2LSB;
- header32.e_machine=cpu;
-
- /* 16-align .rodata in the .o file, just in case */
- paddingSize=sectionHeaders32[4].sh_offset & 0xf;
- if(paddingSize!=0) {
- paddingSize=0x10-paddingSize;
- sectionHeaders32[4].sh_offset+=paddingSize;
- }
-
- sectionHeaders32[4].sh_size=(Elf32_Word)size;
-
- symbols32[1].st_size=(Elf32_Word)size;
-
- /* write .o headers */
- T_FileStream_write(out, &header32, (int32_t)sizeof(header32));
- T_FileStream_write(out, sectionHeaders32, (int32_t)sizeof(sectionHeaders32));
- T_FileStream_write(out, symbols32, (int32_t)sizeof(symbols32));
- } else /* bits==64 */ {
-#ifdef U_ELF64
- header64.e_ident[EI_DATA]= makeBigEndian ? ELFDATA2MSB : ELFDATA2LSB;
- header64.e_machine=cpu;
-
- /* 16-align .rodata in the .o file, just in case */
- paddingSize=sectionHeaders64[4].sh_offset & 0xf;
- if(paddingSize!=0) {
- paddingSize=0x10-paddingSize;
- sectionHeaders64[4].sh_offset+=paddingSize;
- }
-
- sectionHeaders64[4].sh_size=(Elf64_Xword)size;
-
- symbols64[1].st_size=(Elf64_Xword)size;
-
- /* write .o headers */
- T_FileStream_write(out, &header64, (int32_t)sizeof(header64));
- T_FileStream_write(out, sectionHeaders64, (int32_t)sizeof(sectionHeaders64));
- T_FileStream_write(out, symbols64, (int32_t)sizeof(symbols64));
-#endif
- }
-
- T_FileStream_write(out, sectionStrings, (int32_t)sizeof(sectionStrings));
- T_FileStream_write(out, entry, (int32_t)sizeof(entry));
- if(paddingSize!=0) {
- T_FileStream_write(out, padding, paddingSize);
- }
-#elif defined(U_WINDOWS)
- /* populate the .obj headers */
- uprv_memset(&objHeader, 0, sizeof(objHeader));
- uprv_memset(&symbols, 0, sizeof(symbols));
- uprv_memset(&symbolNames, 0, sizeof(symbolNames));
-
- /* write the linker export directive */
- uprv_strcpy(objHeader.linkerOptions, "-export:");
- length=8;
- uprv_strcpy(objHeader.linkerOptions+length, entry);
- length+=entryLength;
- uprv_strcpy(objHeader.linkerOptions+length, ",data ");
- length+=6;
-
- /* set the file header */
- objHeader.fileHeader.Machine=cpu;
- objHeader.fileHeader.NumberOfSections=2;
- objHeader.fileHeader.TimeDateStamp=(DWORD)time(NULL);
- objHeader.fileHeader.PointerToSymbolTable=IMAGE_SIZEOF_FILE_HEADER+2*IMAGE_SIZEOF_SECTION_HEADER+length+size; /* start of symbol table */
- objHeader.fileHeader.NumberOfSymbols=1;
-
- /* set the section for the linker options */
- uprv_strncpy((char *)objHeader.sections[0].Name, ".drectve", 8);
- objHeader.sections[0].SizeOfRawData=length;
- objHeader.sections[0].PointerToRawData=IMAGE_SIZEOF_FILE_HEADER+2*IMAGE_SIZEOF_SECTION_HEADER;
- objHeader.sections[0].Characteristics=IMAGE_SCN_LNK_INFO|IMAGE_SCN_LNK_REMOVE|IMAGE_SCN_ALIGN_1BYTES;
-
- /* set the data section */
- uprv_strncpy((char *)objHeader.sections[1].Name, ".rdata", 6);
- objHeader.sections[1].SizeOfRawData=size;
- objHeader.sections[1].PointerToRawData=IMAGE_SIZEOF_FILE_HEADER+2*IMAGE_SIZEOF_SECTION_HEADER+length;
- objHeader.sections[1].Characteristics=IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_ALIGN_16BYTES|IMAGE_SCN_MEM_READ;
-
- /* set the symbol table */
- if(entryLength<=8) {
- uprv_strncpy((char *)symbols[0].N.ShortName, entry, entryLength);
- symbolNames.sizeofLongNames=4;
- } else {
- symbols[0].N.Name.Short=0;
- symbols[0].N.Name.Long=4;
- symbolNames.sizeofLongNames=4+entryLength+1;
- uprv_strcpy(symbolNames.longNames, entry);
- }
- symbols[0].SectionNumber=2;
- symbols[0].StorageClass=IMAGE_SYM_CLASS_EXTERNAL;
-
- /* write the file header and the linker options section */
- T_FileStream_write(out, &objHeader, objHeader.sections[1].PointerToRawData);
-#else
-# error "Unknown platform for CAN_GENERATE_OBJECTS."
-#endif
-
- /* copy the data file into section 2 */
- for(;;) {
- length=T_FileStream_read(in, buffer, sizeof(buffer));
- if(length==0) {
- break;
- }
- T_FileStream_write(out, buffer, (int32_t)length);
- }
-
-#ifdef U_WINDOWS
- /* write the symbol table */
- T_FileStream_write(out, symbols, IMAGE_SIZEOF_SYMBOL);
- T_FileStream_write(out, &symbolNames, symbolNames.sizeofLongNames);
-#endif
-
- if(T_FileStream_error(in)) {
- fprintf(stderr, "genccode: file read error while generating from file %s\n", filename);
- exit(U_FILE_ACCESS_ERROR);
- }
-
- if(T_FileStream_error(out)) {
- fprintf(stderr, "genccode: file write error while generating from file %s\n", filename);
- exit(U_FILE_ACCESS_ERROR);
- }
-
- T_FileStream_close(out);
- T_FileStream_close(in);
-}
-#endif
+/******************************************************************************
+ * Copyright (C) 2009, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *******************************************************************************
+ */
+#include "unicode/utypes.h"
+
+#ifdef U_WINDOWS
+# define VC_EXTRALEAN
+# define WIN32_LEAN_AND_MEAN
+# define NOUSER
+# define NOSERVICE
+# define NOIME
+# define NOMCX
+#include <windows.h>
+#include <time.h>
+# ifdef __GNUC__
+# define WINDOWS_WITH_GNUC
+# endif
+#endif
+
+#ifdef U_LINUX
+# define U_ELF
+#endif
+
+#ifdef U_ELF
+# include <elf.h>
+# if defined(ELFCLASS64)
+# define U_ELF64
+# endif
+ /* Old elf.h headers may not have EM_X86_64, or have EM_X8664 instead. */
+# ifndef EM_X86_64
+# define EM_X86_64 62
+# endif
+# define ICU_ENTRY_OFFSET 0
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "unicode/putil.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "filestrm.h"
+#include "toolutil.h"
+#include "unicode/uclean.h"
+#include "uoptions.h"
+#include "pkg_genc.h"
+
+#define MAX_COLUMN ((uint32_t)(0xFFFFFFFFU))
+
+#define HEX_0X 0 /* 0x1234 */
+#define HEX_0H 1 /* 01234h */
+
+#if defined(U_WINDOWS) || defined(U_ELF)
+#define CAN_GENERATE_OBJECTS
+#endif
+
+/* prototypes --------------------------------------------------------------- */
+static void
+getOutFilename(const char *inFilename, const char *destdir, char *outFilename, char *entryName, const char *newSuffix, const char *optFilename);
+
+static uint32_t
+write8(FileStream *out, uint8_t byte, uint32_t column);
+
+static uint32_t
+write32(FileStream *out, uint32_t byte, uint32_t column);
+
+#ifdef OS400
+static uint32_t
+write8str(FileStream *out, uint8_t byte, uint32_t column);
+#endif
+/* -------------------------------------------------------------------------- */
+
+/*
+Creating Template Files for New Platforms
+
+Let the cc compiler help you get started.
+Compile this program
+ const unsigned int x[5] = {1, 2, 0xdeadbeef, 0xffffffff, 16};
+with the -S option to produce assembly output.
+
+For example, this will generate array.s:
+gcc -S array.c
+
+This will produce a .s file that may look like this:
+
+ .file "array.c"
+ .version "01.01"
+gcc2_compiled.:
+ .globl x
+ .section .rodata
+ .align 4
+ .type x, at object
+ .size x,20
+x:
+ .long 1
+ .long 2
+ .long -559038737
+ .long -1
+ .long 16
+ .ident "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.1 2.96-85)"
+
+which gives a starting point that will compile, and can be transformed
+to become the template, generally with some consulting of as docs and
+some experimentation.
+
+If you want ICU to automatically use this assembly, you should
+specify "GENCCODE_ASSEMBLY=-a name" in the specific config/mh-* file,
+where the name is the compiler or platform that you used in this
+assemblyHeader data structure.
+*/
+static const struct AssemblyType {
+ const char *name;
+ const char *header;
+ const char *beginLine;
+ const char *footer;
+ int8_t hexType; /* HEX_0X or HEX_0h */
+} assemblyHeader[] = {
+ {"gcc",
+ ".globl %s\n"
+ "\t.section .note.GNU-stack,\"\", at progbits\n"
+ "\t.section .rodata\n"
+ "\t.align 8\n" /* Either align 8 bytes or 2^8 (256) bytes. 8 bytes is needed. */
+ "\t.type %s, at object\n"
+ "%s:\n\n",
+
+ ".long ","",HEX_0X
+ },
+ {"gcc-darwin",
+ /*"\t.section __TEXT,__text,regular,pure_instructions\n"
+ "\t.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32\n"*/
+ ".globl _%s\n"
+ "\t.data\n"
+ "\t.const\n"
+ "\t.align 4\n" /* 1<<4 = 16 */
+ "_%s:\n\n",
+
+ ".long ","",HEX_0X
+ },
+ {"gcc-cygwin",
+ ".globl _%s\n"
+ "\t.section .rodata\n"
+ "\t.align 8\n" /* Either align 8 bytes or 2^8 (256) bytes. 8 bytes is needed. */
+ "_%s:\n\n",
+
+ ".long ","",HEX_0X
+ },
+ {"sun",
+ "\t.section \".rodata\"\n"
+ "\t.align 8\n"
+ ".globl %s\n"
+ "%s:\n",
+
+ ".word ","",HEX_0X
+ },
+ {"sun-x86",
+ "Drodata.rodata:\n"
+ "\t.type Drodata.rodata, at object\n"
+ "\t.size Drodata.rodata,0\n"
+ "\t.globl %s\n"
+ "\t.align 8\n"
+ "%s:\n",
+
+ ".4byte ","",HEX_0X
+ },
+ {"xlc",
+ ".globl %s{RO}\n"
+ "\t.toc\n"
+ "%s:\n"
+ "\t.csect %s{RO}, 4\n",
+
+ ".long ","",HEX_0X
+ },
+ {"aCC-ia64",
+ "\t.file \"%s.s\"\n"
+ "\t.type %s, at object\n"
+ "\t.global %s\n"
+ "\t.secalias .abe$0.rodata, \".rodata\"\n"
+ "\t.section .abe$0.rodata = \"a\", \"progbits\"\n"
+ "\t.align 16\n"
+ "%s::\t",
+
+ "data4 ","",HEX_0X
+ },
+ {"aCC-parisc",
+ "\t.SPACE $TEXT$\n"
+ "\t.SUBSPA $LIT$\n"
+ "%s\n"
+ "\t.EXPORT %s\n"
+ "\t.ALIGN 16\n",
+
+ ".WORD ","",HEX_0X
+ },
+ { "masm",
+ "\tTITLE %s\n"
+ "; generated by genccode\n"
+ ".386\n"
+ ".model flat\n"
+ "\tPUBLIC _%s\n"
+ "ICUDATA_%s\tSEGMENT READONLY PARA PUBLIC FLAT 'DATA'\n"
+ "\tALIGN 16\n"
+ "_%s\tLABEL DWORD\n",
+ "\tDWORD ","\nICUDATA_%s\tENDS\n\tEND\n",HEX_0H
+ }
+};
+
+static int32_t assemblyHeaderIndex = -1;
+static int32_t hexType = HEX_0X;
+
+U_CAPI UBool U_EXPORT2
+checkAssemblyHeaderName(const char* optAssembly) {
+ int32_t idx;
+ assemblyHeaderIndex = -1;
+ for (idx = 0; idx < (int32_t)(sizeof(assemblyHeader)/sizeof(assemblyHeader[0])); idx++) {
+ if (uprv_strcmp(optAssembly, assemblyHeader[idx].name) == 0) {
+ assemblyHeaderIndex = idx;
+ hexType = assemblyHeader[idx].hexType; /* set the hex type */
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+U_CAPI void U_EXPORT2
+printAssemblyHeadersToStdErr(void) {
+ int32_t idx;
+ fprintf(stderr, "%s", assemblyHeader[0].name);
+ for (idx = 1; idx < (int32_t)(sizeof(assemblyHeader)/sizeof(assemblyHeader[0])); idx++) {
+ fprintf(stderr, ", %s", assemblyHeader[idx].name);
+ }
+ fprintf(stderr,
+ ")\n");
+}
+
+U_CAPI void U_EXPORT2
+writeAssemblyCode(const char *filename, const char *destdir, const char *optEntryPoint, const char *optFilename, char *outFilePath) {
+ uint32_t column = MAX_COLUMN;
+ char entry[64];
+ uint32_t buffer[1024];
+ char *bufferStr = (char *)buffer;
+ FileStream *in, *out;
+ size_t i, length;
+
+ in=T_FileStream_open(filename, "rb");
+ if(in==NULL) {
+ fprintf(stderr, "genccode: unable to open input file %s\n", filename);
+ exit(U_FILE_ACCESS_ERROR);
+ }
+
+ getOutFilename(filename, destdir, bufferStr, entry, ".s", optFilename);
+ out=T_FileStream_open(bufferStr, "w");
+ if(out==NULL) {
+ fprintf(stderr, "genccode: unable to open output file %s\n", bufferStr);
+ exit(U_FILE_ACCESS_ERROR);
+ }
+
+ if (outFilePath != NULL) {
+ uprv_strcpy(outFilePath, bufferStr);
+ }
+
+#ifdef WINDOWS_WITH_GNUC
+ /* Need to fix the file seperator character when using MinGW. */
+ swapFileSepChar(outFilePath, U_FILE_SEP_CHAR, '/');
+#endif
+
+ if(optEntryPoint != NULL) {
+ uprv_strcpy(entry, optEntryPoint);
+ uprv_strcat(entry, "_dat");
+ }
+
+ /* turn dashes or dots in the entry name into underscores */
+ length=uprv_strlen(entry);
+ for(i=0; i<length; ++i) {
+ if(entry[i]=='-' || entry[i]=='.') {
+ entry[i]='_';
+ }
+ }
+
+ sprintf(bufferStr, assemblyHeader[assemblyHeaderIndex].header,
+ entry, entry, entry, entry,
+ entry, entry, entry, entry);
+ T_FileStream_writeLine(out, bufferStr);
+ T_FileStream_writeLine(out, assemblyHeader[assemblyHeaderIndex].beginLine);
+
+ for(;;) {
+ length=T_FileStream_read(in, buffer, sizeof(buffer));
+ if(length==0) {
+ break;
+ }
+ if (length != sizeof(buffer)) {
+ /* pad with extra 0's when at the end of the file */
+ for(i=0; i < (length % sizeof(uint32_t)); ++i) {
+ buffer[length+i] = 0;
+ }
+ }
+ for(i=0; i<(length/sizeof(buffer[0])); i++) {
+ column = write32(out, buffer[i], column);
+ }
+ }
+
+ T_FileStream_writeLine(out, "\n");
+
+ sprintf(bufferStr, assemblyHeader[assemblyHeaderIndex].footer,
+ entry, entry, entry, entry,
+ entry, entry, entry, entry);
+ T_FileStream_writeLine(out, bufferStr);
+
+ if(T_FileStream_error(in)) {
+ fprintf(stderr, "genccode: file read error while generating from file %s\n", filename);
+ exit(U_FILE_ACCESS_ERROR);
+ }
+
+ if(T_FileStream_error(out)) {
+ fprintf(stderr, "genccode: file write error while generating from file %s\n", filename);
+ exit(U_FILE_ACCESS_ERROR);
+ }
+
+ T_FileStream_close(out);
+ T_FileStream_close(in);
+}
+
+U_CAPI void U_EXPORT2
+writeCCode(const char *filename, const char *destdir, const char *optName, const char *optFilename, char *outFilePath) {
+ uint32_t column = MAX_COLUMN;
+ char buffer[4096], entry[64];
+ FileStream *in, *out;
+ size_t i, length;
+
+ in=T_FileStream_open(filename, "rb");
+ if(in==NULL) {
+ fprintf(stderr, "genccode: unable to open input file %s\n", filename);
+ exit(U_FILE_ACCESS_ERROR);
+ }
+
+ if(optName != NULL) { /* prepend 'icudt28_' */
+ strcpy(entry, optName);
+ strcat(entry, "_");
+ } else {
+ entry[0] = 0;
+ }
+
+ getOutFilename(filename, destdir, buffer, entry+uprv_strlen(entry), ".c", optFilename);
+ if (outFilePath != NULL) {
+ uprv_strcpy(outFilePath, buffer);
+ }
+ out=T_FileStream_open(buffer, "w");
+ if(out==NULL) {
+ fprintf(stderr, "genccode: unable to open output file %s\n", buffer);
+ exit(U_FILE_ACCESS_ERROR);
+ }
+
+ /* turn dashes or dots in the entry name into underscores */
+ length=uprv_strlen(entry);
+ for(i=0; i<length; ++i) {
+ if(entry[i]=='-' || entry[i]=='.') {
+ entry[i]='_';
+ }
+ }
+
+#ifdef OS400
+ /*
+ TODO: Fix this once the compiler implements this feature. Keep in sync with udatamem.c
+
+ This is here because this platform can't currently put
+ const data into the read-only pages of an object or
+ shared library (service program). Only strings are allowed in read-only
+ pages, so we use char * strings to store the data.
+
+ In order to prevent the beginning of the data from ever matching the
+ magic numbers we must still use the initial double.
+ [grhoten 4/24/2003]
+ */
+ sprintf(buffer,
+ "#define U_DISABLE_RENAMING 1\n"
+ "#include \"unicode/umachine.h\"\n"
+ "U_CDECL_BEGIN\n"
+ "const struct {\n"
+ " double bogus;\n"
+ " const char *bytes; \n"
+ "} %s={ 0.0, \n",
+ entry);
+ T_FileStream_writeLine(out, buffer);
+
+ for(;;) {
+ length=T_FileStream_read(in, buffer, sizeof(buffer));
+ if(length==0) {
+ break;
+ }
+ for(i=0; i<length; ++i) {
+ column = write8str(out, (uint8_t)buffer[i], column);
+ }
+ }
+
+ T_FileStream_writeLine(out, "\"\n};\nU_CDECL_END\n");
+#else
+ /* Function renaming shouldn't be done in data */
+ sprintf(buffer,
+ "#define U_DISABLE_RENAMING 1\n"
+ "#include \"unicode/umachine.h\"\n"
+ "U_CDECL_BEGIN\n"
+ "const struct {\n"
+ " double bogus;\n"
+ " uint8_t bytes[%ld]; \n"
+ "} %s={ 0.0, {\n",
+ (long)T_FileStream_size(in), entry);
+ T_FileStream_writeLine(out, buffer);
+
+ for(;;) {
+ length=T_FileStream_read(in, buffer, sizeof(buffer));
+ if(length==0) {
+ break;
+ }
+ for(i=0; i<length; ++i) {
+ column = write8(out, (uint8_t)buffer[i], column);
+ }
+ }
+
+ T_FileStream_writeLine(out, "\n}\n};\nU_CDECL_END\n");
+#endif
+
+ if(T_FileStream_error(in)) {
+ fprintf(stderr, "genccode: file read error while generating from file %s\n", filename);
+ exit(U_FILE_ACCESS_ERROR);
+ }
+
+ if(T_FileStream_error(out)) {
+ fprintf(stderr, "genccode: file write error while generating from file %s\n", filename);
+ exit(U_FILE_ACCESS_ERROR);
+ }
+
+ T_FileStream_close(out);
+ T_FileStream_close(in);
+}
+
+static uint32_t
+write32(FileStream *out, uint32_t bitField, uint32_t column) {
+ int32_t i;
+ char bitFieldStr[64]; /* This is more bits than needed for a 32-bit number */
+ char *s = bitFieldStr;
+ uint8_t *ptrIdx = (uint8_t *)&bitField;
+ static const char hexToStr[16] = {
+ '0','1','2','3',
+ '4','5','6','7',
+ '8','9','A','B',
+ 'C','D','E','F'
+ };
+
+ /* write the value, possibly with comma and newline */
+ if(column==MAX_COLUMN) {
+ /* first byte */
+ column=1;
+ } else if(column<32) {
+ *(s++)=',';
+ ++column;
+ } else {
+ *(s++)='\n';
+ uprv_strcpy(s, assemblyHeader[assemblyHeaderIndex].beginLine);
+ s+=uprv_strlen(s);
+ column=1;
+ }
+
+ if (bitField < 10) {
+ /* It's a small number. Don't waste the space for 0x */
+ *(s++)=hexToStr[bitField];
+ }
+ else {
+ int seenNonZero = 0; /* This is used to remove leading zeros */
+
+ if(hexType==HEX_0X) {
+ *(s++)='0';
+ *(s++)='x';
+ } else if(hexType==HEX_0H) {
+ *(s++)='0';
+ }
+
+ /* This creates a 32-bit field */
+#if U_IS_BIG_ENDIAN
+ for (i = 0; i < sizeof(uint32_t); i++)
+#else
+ for (i = sizeof(uint32_t)-1; i >= 0 ; i--)
+#endif
+ {
+ uint8_t value = ptrIdx[i];
+ if (value || seenNonZero) {
+ *(s++)=hexToStr[value>>4];
+ *(s++)=hexToStr[value&0xF];
+ seenNonZero = 1;
+ }
+ }
+ if(hexType==HEX_0H) {
+ *(s++)='h';
+ }
+ }
+
+ *(s++)=0;
+ T_FileStream_writeLine(out, bitFieldStr);
+ return column;
+}
+
+static uint32_t
+write8(FileStream *out, uint8_t byte, uint32_t column) {
+ char s[4];
+ int i=0;
+
+ /* convert the byte value to a string */
+ if(byte>=100) {
+ s[i++]=(char)('0'+byte/100);
+ byte%=100;
+ }
+ if(i>0 || byte>=10) {
+ s[i++]=(char)('0'+byte/10);
+ byte%=10;
+ }
+ s[i++]=(char)('0'+byte);
+ s[i]=0;
+
+ /* write the value, possibly with comma and newline */
+ if(column==MAX_COLUMN) {
+ /* first byte */
+ column=1;
+ } else if(column<16) {
+ T_FileStream_writeLine(out, ",");
+ ++column;
+ } else {
+ T_FileStream_writeLine(out, ",\n");
+ column=1;
+ }
+ T_FileStream_writeLine(out, s);
+ return column;
+}
+
+#ifdef OS400
+static uint32_t
+write8str(FileStream *out, uint8_t byte, uint32_t column) {
+ char s[8];
+
+ if (byte > 7)
+ sprintf(s, "\\x%X", byte);
+ else
+ sprintf(s, "\\%X", byte);
+
+ /* write the value, possibly with comma and newline */
+ if(column==MAX_COLUMN) {
+ /* first byte */
+ column=1;
+ T_FileStream_writeLine(out, "\"");
+ } else if(column<24) {
+ ++column;
+ } else {
+ T_FileStream_writeLine(out, "\"\n\"");
+ column=1;
+ }
+ T_FileStream_writeLine(out, s);
+ return column;
+}
+#endif
+
+static void
+getOutFilename(const char *inFilename, const char *destdir, char *outFilename, char *entryName, const char *newSuffix, const char *optFilename) {
+ const char *basename=findBasename(inFilename), *suffix=uprv_strrchr(basename, '.');
+
+ /* copy path */
+ if(destdir!=NULL && *destdir!=0) {
+ do {
+ *outFilename++=*destdir++;
+ } while(*destdir!=0);
+ if(*(outFilename-1)!=U_FILE_SEP_CHAR) {
+ *outFilename++=U_FILE_SEP_CHAR;
+ }
+ inFilename=basename;
+ } else {
+ while(inFilename<basename) {
+ *outFilename++=*inFilename++;
+ }
+ }
+
+ if(suffix==NULL) {
+ /* the filename does not have a suffix */
+ uprv_strcpy(entryName, inFilename);
+ if(optFilename != NULL) {
+ uprv_strcpy(outFilename, optFilename);
+ } else {
+ uprv_strcpy(outFilename, inFilename);
+ }
+ uprv_strcat(outFilename, newSuffix);
+ } else {
+ char *saveOutFilename = outFilename;
+ /* copy basename */
+ while(inFilename<suffix) {
+ if(*inFilename=='-') {
+ /* iSeries cannot have '-' in the .o objects. */
+ *outFilename++=*entryName++='_';
+ inFilename++;
+ }
+ else {
+ *outFilename++=*entryName++=*inFilename++;
+ }
+ }
+
+ /* replace '.' by '_' */
+ *outFilename++=*entryName++='_';
+ ++inFilename;
+
+ /* copy suffix */
+ while(*inFilename!=0) {
+ *outFilename++=*entryName++=*inFilename++;
+ }
+
+ *entryName=0;
+
+ if(optFilename != NULL) {
+ uprv_strcpy(saveOutFilename, optFilename);
+ uprv_strcat(saveOutFilename, newSuffix);
+ } else {
+ /* add ".c" */
+ uprv_strcpy(outFilename, newSuffix);
+ }
+ }
+}
+
+#ifdef CAN_GENERATE_OBJECTS
+static void
+getArchitecture(uint16_t *pCPU, uint16_t *pBits, UBool *pIsBigEndian, const char *optMatchArch) {
+ int64_t buffer[256];
+ const char *filename;
+ FileStream *in;
+ int32_t length;
+
+#ifdef U_ELF
+ /* Pointer to ELF header. Elf32_Ehdr and ELF64_Ehdr are identical for the necessary fields. */
+ const Elf32_Ehdr *pHeader32;
+#elif defined(U_WINDOWS)
+ const IMAGE_FILE_HEADER *pHeader;
+#else
+# error "Unknown platform for CAN_GENERATE_OBJECTS."
+#endif
+
+ if(optMatchArch != NULL) {
+ filename=optMatchArch;
+ } else {
+ /* set defaults */
+#ifdef U_ELF
+ /* set EM_386 because elf.h does not provide better defaults */
+ *pCPU=EM_386;
+ *pBits=32;
+ *pIsBigEndian=(UBool)(U_IS_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB);
+#elif defined(U_WINDOWS)
+/* _M_IA64 should be defined in windows.h */
+# if defined(_M_IA64)
+ *pCPU=IMAGE_FILE_MACHINE_IA64;
+# elif defined(_M_AMD64)
+ *pCPU=IMAGE_FILE_MACHINE_AMD64;
+# else
+ *pCPU=IMAGE_FILE_MACHINE_I386;
+# endif
+ *pBits= *pCPU==IMAGE_FILE_MACHINE_I386 ? 32 : 64;
+ *pIsBigEndian=FALSE;
+#else
+# error "Unknown platform for CAN_GENERATE_OBJECTS."
+#endif
+ return;
+ }
+
+ in=T_FileStream_open(filename, "rb");
+ if(in==NULL) {
+ fprintf(stderr, "genccode: unable to open match-arch file %s\n", filename);
+ exit(U_FILE_ACCESS_ERROR);
+ }
+ length=T_FileStream_read(in, buffer, sizeof(buffer));
+
+#ifdef U_ELF
+ if(length<sizeof(Elf32_Ehdr)) {
+ fprintf(stderr, "genccode: match-arch file %s is too short\n", filename);
+ exit(U_UNSUPPORTED_ERROR);
+ }
+ pHeader32=(const Elf32_Ehdr *)buffer;
+ if(
+ pHeader32->e_ident[0]!=ELFMAG0 ||
+ pHeader32->e_ident[1]!=ELFMAG1 ||
+ pHeader32->e_ident[2]!=ELFMAG2 ||
+ pHeader32->e_ident[3]!=ELFMAG3 ||
+ pHeader32->e_ident[EI_CLASS]<ELFCLASS32 || pHeader32->e_ident[EI_CLASS]>ELFCLASS64
+ ) {
+ fprintf(stderr, "genccode: match-arch file %s is not an ELF object file, or not supported\n", filename);
+ exit(U_UNSUPPORTED_ERROR);
+ }
+
+ *pBits= pHeader32->e_ident[EI_CLASS]==ELFCLASS32 ? 32 : 64; /* only 32 or 64: see check above */
+#ifdef U_ELF64
+ if(*pBits!=32 && *pBits!=64) {
+ fprintf(stderr, "genccode: currently only supports 32-bit and 64-bit ELF format\n");
+ exit(U_UNSUPPORTED_ERROR);
+ }
+#else
+ if(*pBits!=32) {
+ fprintf(stderr, "genccode: built with elf.h missing 64-bit definitions\n");
+ exit(U_UNSUPPORTED_ERROR);
+ }
+#endif
+
+ *pIsBigEndian=(UBool)(pHeader32->e_ident[EI_DATA]==ELFDATA2MSB);
+ if(*pIsBigEndian!=U_IS_BIG_ENDIAN) {
+ fprintf(stderr, "genccode: currently only same-endianness ELF formats are supported\n");
+ exit(U_UNSUPPORTED_ERROR);
+ }
+ /* TODO: Support byte swapping */
+
+ *pCPU=pHeader32->e_machine;
+#elif defined(U_WINDOWS)
+ if(length<sizeof(IMAGE_FILE_HEADER)) {
+ fprintf(stderr, "genccode: match-arch file %s is too short\n", filename);
+ exit(U_UNSUPPORTED_ERROR);
+ }
+ pHeader=(const IMAGE_FILE_HEADER *)buffer;
+ *pCPU=pHeader->Machine;
+ /*
+ * The number of bits is implicit with the Machine value.
+ * *pBits is ignored in the calling code, so this need not be precise.
+ */
+ *pBits= *pCPU==IMAGE_FILE_MACHINE_I386 ? 32 : 64;
+ /* Windows always runs on little-endian CPUs. */
+ *pIsBigEndian=FALSE;
+#else
+# error "Unknown platform for CAN_GENERATE_OBJECTS."
+#endif
+
+ T_FileStream_close(in);
+}
+
+U_CAPI void U_EXPORT2
+writeObjectCode(const char *filename, const char *destdir, const char *optEntryPoint, const char *optMatchArch, const char *optFilename, char *outFilePath) {
+ /* common variables */
+ char buffer[4096], entry[40]={ 0 };
+ FileStream *in, *out;
+ const char *newSuffix;
+ int32_t i, entryLength, length, size, entryOffset=0, entryLengthOffset=0;
+
+ uint16_t cpu, bits;
+ UBool makeBigEndian;
+
+ /* platform-specific variables and initialization code */
+#ifdef U_ELF
+ /* 32-bit Elf file header */
+ static Elf32_Ehdr header32={
+ {
+ /* e_ident[] */
+ ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
+ ELFCLASS32,
+ U_IS_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB,
+ EV_CURRENT /* EI_VERSION */
+ },
+ ET_REL,
+ EM_386,
+ EV_CURRENT, /* e_version */
+ 0, /* e_entry */
+ 0, /* e_phoff */
+ (Elf32_Off)sizeof(Elf32_Ehdr), /* e_shoff */
+ 0, /* e_flags */
+ (Elf32_Half)sizeof(Elf32_Ehdr), /* eh_size */
+ 0, /* e_phentsize */
+ 0, /* e_phnum */
+ (Elf32_Half)sizeof(Elf32_Shdr), /* e_shentsize */
+ 5, /* e_shnum */
+ 2 /* e_shstrndx */
+ };
+
+ /* 32-bit Elf section header table */
+ static Elf32_Shdr sectionHeaders32[5]={
+ { /* SHN_UNDEF */
+ 0
+ },
+ { /* .symtab */
+ 1, /* sh_name */
+ SHT_SYMTAB,
+ 0, /* sh_flags */
+ 0, /* sh_addr */
+ (Elf32_Off)(sizeof(header32)+sizeof(sectionHeaders32)), /* sh_offset */
+ (Elf32_Word)(2*sizeof(Elf32_Sym)), /* sh_size */
+ 3, /* sh_link=sect hdr index of .strtab */
+ 1, /* sh_info=One greater than the symbol table index of the last
+ * local symbol (with STB_LOCAL). */
+ 4, /* sh_addralign */
+ (Elf32_Word)(sizeof(Elf32_Sym)) /* sh_entsize */
+ },
+ { /* .shstrtab */
+ 9, /* sh_name */
+ SHT_STRTAB,
+ 0, /* sh_flags */
+ 0, /* sh_addr */
+ (Elf32_Off)(sizeof(header32)+sizeof(sectionHeaders32)+2*sizeof(Elf32_Sym)), /* sh_offset */
+ 40, /* sh_size */
+ 0, /* sh_link */
+ 0, /* sh_info */
+ 1, /* sh_addralign */
+ 0 /* sh_entsize */
+ },
+ { /* .strtab */
+ 19, /* sh_name */
+ SHT_STRTAB,
+ 0, /* sh_flags */
+ 0, /* sh_addr */
+ (Elf32_Off)(sizeof(header32)+sizeof(sectionHeaders32)+2*sizeof(Elf32_Sym)+40), /* sh_offset */
+ (Elf32_Word)sizeof(entry), /* sh_size */
+ 0, /* sh_link */
+ 0, /* sh_info */
+ 1, /* sh_addralign */
+ 0 /* sh_entsize */
+ },
+ { /* .rodata */
+ 27, /* sh_name */
+ SHT_PROGBITS,
+ SHF_ALLOC, /* sh_flags */
+ 0, /* sh_addr */
+ (Elf32_Off)(sizeof(header32)+sizeof(sectionHeaders32)+2*sizeof(Elf32_Sym)+40+sizeof(entry)), /* sh_offset */
+ 0, /* sh_size */
+ 0, /* sh_link */
+ 0, /* sh_info */
+ 16, /* sh_addralign */
+ 0 /* sh_entsize */
+ }
+ };
+
+ /* symbol table */
+ static Elf32_Sym symbols32[2]={
+ { /* STN_UNDEF */
+ 0
+ },
+ { /* data entry point */
+ 1, /* st_name */
+ 0, /* st_value */
+ 0, /* st_size */
+ ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT),
+ 0, /* st_other */
+ 4 /* st_shndx=index of related section table entry */
+ }
+ };
+
+ /* section header string table, with decimal string offsets */
+ static const char sectionStrings[40]=
+ /* 0 */ "\0"
+ /* 1 */ ".symtab\0"
+ /* 9 */ ".shstrtab\0"
+ /* 19 */ ".strtab\0"
+ /* 27 */ ".rodata\0"
+ /* 35 */ "\0\0\0\0"; /* contains terminating NUL */
+ /* 40: padded to multiple of 8 bytes */
+
+ /*
+ * Use entry[] for the string table which will contain only the
+ * entry point name.
+ * entry[0] must be 0 (NUL)
+ * The entry point name can be up to 38 characters long (sizeof(entry)-2).
+ */
+
+ /* 16-align .rodata in the .o file, just in case */
+ static const char padding[16]={ 0 };
+ int32_t paddingSize;
+
+#ifdef U_ELF64
+ /* 64-bit Elf file header */
+ static Elf64_Ehdr header64={
+ {
+ /* e_ident[] */
+ ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
+ ELFCLASS64,
+ U_IS_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB,
+ EV_CURRENT /* EI_VERSION */
+ },
+ ET_REL,
+ EM_X86_64,
+ EV_CURRENT, /* e_version */
+ 0, /* e_entry */
+ 0, /* e_phoff */
+ (Elf64_Off)sizeof(Elf64_Ehdr), /* e_shoff */
+ 0, /* e_flags */
+ (Elf64_Half)sizeof(Elf64_Ehdr), /* eh_size */
+ 0, /* e_phentsize */
+ 0, /* e_phnum */
+ (Elf64_Half)sizeof(Elf64_Shdr), /* e_shentsize */
+ 5, /* e_shnum */
+ 2 /* e_shstrndx */
+ };
+
+ /* 64-bit Elf section header table */
+ static Elf64_Shdr sectionHeaders64[5]={
+ { /* SHN_UNDEF */
+ 0
+ },
+ { /* .symtab */
+ 1, /* sh_name */
+ SHT_SYMTAB,
+ 0, /* sh_flags */
+ 0, /* sh_addr */
+ (Elf64_Off)(sizeof(header64)+sizeof(sectionHeaders64)), /* sh_offset */
+ (Elf64_Xword)(2*sizeof(Elf64_Sym)), /* sh_size */
+ 3, /* sh_link=sect hdr index of .strtab */
+ 1, /* sh_info=One greater than the symbol table index of the last
+ * local symbol (with STB_LOCAL). */
+ 4, /* sh_addralign */
+ (Elf64_Xword)(sizeof(Elf64_Sym)) /* sh_entsize */
+ },
+ { /* .shstrtab */
+ 9, /* sh_name */
+ SHT_STRTAB,
+ 0, /* sh_flags */
+ 0, /* sh_addr */
+ (Elf64_Off)(sizeof(header64)+sizeof(sectionHeaders64)+2*sizeof(Elf64_Sym)), /* sh_offset */
+ 40, /* sh_size */
+ 0, /* sh_link */
+ 0, /* sh_info */
+ 1, /* sh_addralign */
+ 0 /* sh_entsize */
+ },
+ { /* .strtab */
+ 19, /* sh_name */
+ SHT_STRTAB,
+ 0, /* sh_flags */
+ 0, /* sh_addr */
+ (Elf64_Off)(sizeof(header64)+sizeof(sectionHeaders64)+2*sizeof(Elf64_Sym)+40), /* sh_offset */
+ (Elf64_Xword)sizeof(entry), /* sh_size */
+ 0, /* sh_link */
+ 0, /* sh_info */
+ 1, /* sh_addralign */
+ 0 /* sh_entsize */
+ },
+ { /* .rodata */
+ 27, /* sh_name */
+ SHT_PROGBITS,
+ SHF_ALLOC, /* sh_flags */
+ 0, /* sh_addr */
+ (Elf64_Off)(sizeof(header64)+sizeof(sectionHeaders64)+2*sizeof(Elf64_Sym)+40+sizeof(entry)), /* sh_offset */
+ 0, /* sh_size */
+ 0, /* sh_link */
+ 0, /* sh_info */
+ 16, /* sh_addralign */
+ 0 /* sh_entsize */
+ }
+ };
+
+ /*
+ * 64-bit symbol table
+ * careful: different order of items compared with Elf32_sym!
+ */
+ static Elf64_Sym symbols64[2]={
+ { /* STN_UNDEF */
+ 0
+ },
+ { /* data entry point */
+ 1, /* st_name */
+ ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT),
+ 0, /* st_other */
+ 4, /* st_shndx=index of related section table entry */
+ 0, /* st_value */
+ 0 /* st_size */
+ }
+ };
+
+#endif /* U_ELF64 */
+
+ /* entry[] have a leading NUL */
+ entryOffset=1;
+
+ /* in the common code, count entryLength from after the NUL */
+ entryLengthOffset=1;
+
+ newSuffix=".o";
+
+#elif defined(U_WINDOWS)
+ struct {
+ IMAGE_FILE_HEADER fileHeader;
+ IMAGE_SECTION_HEADER sections[2];
+ char linkerOptions[100];
+ } objHeader;
+ IMAGE_SYMBOL symbols[1];
+ struct {
+ DWORD sizeofLongNames;
+ char longNames[100];
+ } symbolNames;
+
+ /*
+ * entry sometimes have a leading '_'
+ * overwritten if entryOffset==0 depending on the target platform
+ * see check for cpu below
+ */
+ entry[0]='_';
+
+ newSuffix=".obj";
+#else
+# error "Unknown platform for CAN_GENERATE_OBJECTS."
+#endif
+
+ /* deal with options, files and the entry point name */
+ getArchitecture(&cpu, &bits, &makeBigEndian, optMatchArch);
+ printf("genccode: --match-arch cpu=%hu bits=%hu big-endian=%hu\n", cpu, bits, makeBigEndian);
+#ifdef U_WINDOWS
+ if(cpu==IMAGE_FILE_MACHINE_I386) {
+ entryOffset=1;
+ }
+#endif
+
+ in=T_FileStream_open(filename, "rb");
+ if(in==NULL) {
+ fprintf(stderr, "genccode: unable to open input file %s\n", filename);
+ exit(U_FILE_ACCESS_ERROR);
+ }
+ size=T_FileStream_size(in);
+
+ getOutFilename(filename, destdir, buffer, entry+entryOffset, newSuffix, optFilename);
+ if (outFilePath != NULL) {
+ uprv_strcpy(outFilePath, buffer);
+ }
+
+ if(optEntryPoint != NULL) {
+ uprv_strcpy(entry+entryOffset, optEntryPoint);
+ uprv_strcat(entry+entryOffset, "_dat");
+ }
+ /* turn dashes in the entry name into underscores */
+ entryLength=(int32_t)uprv_strlen(entry+entryLengthOffset);
+ for(i=0; i<entryLength; ++i) {
+ if(entry[entryLengthOffset+i]=='-') {
+ entry[entryLengthOffset+i]='_';
+ }
+ }
+
+ /* open the output file */
+ out=T_FileStream_open(buffer, "wb");
+ if(out==NULL) {
+ fprintf(stderr, "genccode: unable to open output file %s\n", buffer);
+ exit(U_FILE_ACCESS_ERROR);
+ }
+
+#ifdef U_ELF
+ if(bits==32) {
+ header32.e_ident[EI_DATA]= makeBigEndian ? ELFDATA2MSB : ELFDATA2LSB;
+ header32.e_machine=cpu;
+
+ /* 16-align .rodata in the .o file, just in case */
+ paddingSize=sectionHeaders32[4].sh_offset & 0xf;
+ if(paddingSize!=0) {
+ paddingSize=0x10-paddingSize;
+ sectionHeaders32[4].sh_offset+=paddingSize;
+ }
+
+ sectionHeaders32[4].sh_size=(Elf32_Word)size;
+
+ symbols32[1].st_size=(Elf32_Word)size;
+
+ /* write .o headers */
+ T_FileStream_write(out, &header32, (int32_t)sizeof(header32));
+ T_FileStream_write(out, sectionHeaders32, (int32_t)sizeof(sectionHeaders32));
+ T_FileStream_write(out, symbols32, (int32_t)sizeof(symbols32));
+ } else /* bits==64 */ {
+#ifdef U_ELF64
+ header64.e_ident[EI_DATA]= makeBigEndian ? ELFDATA2MSB : ELFDATA2LSB;
+ header64.e_machine=cpu;
+
+ /* 16-align .rodata in the .o file, just in case */
+ paddingSize=sectionHeaders64[4].sh_offset & 0xf;
+ if(paddingSize!=0) {
+ paddingSize=0x10-paddingSize;
+ sectionHeaders64[4].sh_offset+=paddingSize;
+ }
+
+ sectionHeaders64[4].sh_size=(Elf64_Xword)size;
+
+ symbols64[1].st_size=(Elf64_Xword)size;
+
+ /* write .o headers */
+ T_FileStream_write(out, &header64, (int32_t)sizeof(header64));
+ T_FileStream_write(out, sectionHeaders64, (int32_t)sizeof(sectionHeaders64));
+ T_FileStream_write(out, symbols64, (int32_t)sizeof(symbols64));
+#endif
+ }
+
+ T_FileStream_write(out, sectionStrings, (int32_t)sizeof(sectionStrings));
+ T_FileStream_write(out, entry, (int32_t)sizeof(entry));
+ if(paddingSize!=0) {
+ T_FileStream_write(out, padding, paddingSize);
+ }
+#elif defined(U_WINDOWS)
+ /* populate the .obj headers */
+ uprv_memset(&objHeader, 0, sizeof(objHeader));
+ uprv_memset(&symbols, 0, sizeof(symbols));
+ uprv_memset(&symbolNames, 0, sizeof(symbolNames));
+
+ /* write the linker export directive */
+ uprv_strcpy(objHeader.linkerOptions, "-export:");
+ length=8;
+ uprv_strcpy(objHeader.linkerOptions+length, entry);
+ length+=entryLength;
+ uprv_strcpy(objHeader.linkerOptions+length, ",data ");
+ length+=6;
+
+ /* set the file header */
+ objHeader.fileHeader.Machine=cpu;
+ objHeader.fileHeader.NumberOfSections=2;
+ objHeader.fileHeader.TimeDateStamp=(DWORD)time(NULL);
+ objHeader.fileHeader.PointerToSymbolTable=IMAGE_SIZEOF_FILE_HEADER+2*IMAGE_SIZEOF_SECTION_HEADER+length+size; /* start of symbol table */
+ objHeader.fileHeader.NumberOfSymbols=1;
+
+ /* set the section for the linker options */
+ uprv_strncpy((char *)objHeader.sections[0].Name, ".drectve", 8);
+ objHeader.sections[0].SizeOfRawData=length;
+ objHeader.sections[0].PointerToRawData=IMAGE_SIZEOF_FILE_HEADER+2*IMAGE_SIZEOF_SECTION_HEADER;
+ objHeader.sections[0].Characteristics=IMAGE_SCN_LNK_INFO|IMAGE_SCN_LNK_REMOVE|IMAGE_SCN_ALIGN_1BYTES;
+
+ /* set the data section */
+ uprv_strncpy((char *)objHeader.sections[1].Name, ".rdata", 6);
+ objHeader.sections[1].SizeOfRawData=size;
+ objHeader.sections[1].PointerToRawData=IMAGE_SIZEOF_FILE_HEADER+2*IMAGE_SIZEOF_SECTION_HEADER+length;
+ objHeader.sections[1].Characteristics=IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_ALIGN_16BYTES|IMAGE_SCN_MEM_READ;
+
+ /* set the symbol table */
+ if(entryLength<=8) {
+ uprv_strncpy((char *)symbols[0].N.ShortName, entry, entryLength);
+ symbolNames.sizeofLongNames=4;
+ } else {
+ symbols[0].N.Name.Short=0;
+ symbols[0].N.Name.Long=4;
+ symbolNames.sizeofLongNames=4+entryLength+1;
+ uprv_strcpy(symbolNames.longNames, entry);
+ }
+ symbols[0].SectionNumber=2;
+ symbols[0].StorageClass=IMAGE_SYM_CLASS_EXTERNAL;
+
+ /* write the file header and the linker options section */
+ T_FileStream_write(out, &objHeader, objHeader.sections[1].PointerToRawData);
+#else
+# error "Unknown platform for CAN_GENERATE_OBJECTS."
+#endif
+
+ /* copy the data file into section 2 */
+ for(;;) {
+ length=T_FileStream_read(in, buffer, sizeof(buffer));
+ if(length==0) {
+ break;
+ }
+ T_FileStream_write(out, buffer, (int32_t)length);
+ }
+
+#ifdef U_WINDOWS
+ /* write the symbol table */
+ T_FileStream_write(out, symbols, IMAGE_SIZEOF_SYMBOL);
+ T_FileStream_write(out, &symbolNames, symbolNames.sizeofLongNames);
+#endif
+
+ if(T_FileStream_error(in)) {
+ fprintf(stderr, "genccode: file read error while generating from file %s\n", filename);
+ exit(U_FILE_ACCESS_ERROR);
+ }
+
+ if(T_FileStream_error(out)) {
+ fprintf(stderr, "genccode: file write error while generating from file %s\n", filename);
+ exit(U_FILE_ACCESS_ERROR);
+ }
+
+ T_FileStream_close(out);
+ T_FileStream_close(in);
+}
+#endif
Modified: trunk/source/tools/toolutil/pkg_genc.h
===================================================================
--- trunk/source/tools/toolutil/pkg_genc.h 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/tools/toolutil/pkg_genc.h 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,27 +1,27 @@
-/******************************************************************************
- * Copyright (C) 2008-2009, International Business Machines
- * Corporation and others. All Rights Reserved.
- *******************************************************************************
- */
-
-#ifndef __PKG_GENC_H__
-#define __PKG_GENC_H__
-
-#include "unicode/utypes.h"
-
-U_INTERNAL void U_EXPORT2
-printAssemblyHeadersToStdErr();
-
-U_INTERNAL UBool U_EXPORT2
-checkAssemblyHeaderName(const char* optAssembly);
-
-U_INTERNAL void U_EXPORT2
-writeCCode(const char *filename, const char *destdir, const char *optName, const char *optFilename, char *outFilePath);
-
-U_INTERNAL void U_EXPORT2
-writeAssemblyCode(const char *filename, const char *destdir, const char *optEntryPoint, const char *optFilename, char *outFilePath);
-
-U_INTERNAL void U_EXPORT2
-writeObjectCode(const char *filename, const char *destdir, const char *optEntryPoint, const char *optMatchArch, const char *optFilename, char *outFilePath);
-
-#endif
+/******************************************************************************
+ * Copyright (C) 2008-2009, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *******************************************************************************
+ */
+
+#ifndef __PKG_GENC_H__
+#define __PKG_GENC_H__
+
+#include "unicode/utypes.h"
+
+U_INTERNAL void U_EXPORT2
+printAssemblyHeadersToStdErr();
+
+U_INTERNAL UBool U_EXPORT2
+checkAssemblyHeaderName(const char* optAssembly);
+
+U_INTERNAL void U_EXPORT2
+writeCCode(const char *filename, const char *destdir, const char *optName, const char *optFilename, char *outFilePath);
+
+U_INTERNAL void U_EXPORT2
+writeAssemblyCode(const char *filename, const char *destdir, const char *optEntryPoint, const char *optFilename, char *outFilePath);
+
+U_INTERNAL void U_EXPORT2
+writeObjectCode(const char *filename, const char *destdir, const char *optEntryPoint, const char *optMatchArch, const char *optFilename, char *outFilePath);
+
+#endif
Modified: trunk/source/tools/toolutil/pkg_gencmn.c
===================================================================
--- trunk/source/tools/toolutil/pkg_gencmn.c 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/tools/toolutil/pkg_gencmn.c 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,546 +1,546 @@
-/******************************************************************************
- * Copyright (C) 2008, International Business Machines
- * Corporation and others. All Rights Reserved.
- *******************************************************************************
- */
-#include "unicode/utypes.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "unicode/utypes.h"
-#include "unicode/putil.h"
-#include "cmemory.h"
-#include "cstring.h"
-#include "filestrm.h"
-#include "toolutil.h"
-#include "unicode/uclean.h"
-#include "unewdata.h"
-#include "putilimp.h"
-#include "pkg_gencmn.h"
-
-#define STRING_STORE_SIZE 100000
-#define MAX_FILE_COUNT 2000
-
-#define COMMON_DATA_NAME U_ICUDATA_NAME
-#define DATA_TYPE "dat"
-
-/* ICU package data file format (.dat files) ------------------------------- ***
-
-Description of the data format after the usual ICU data file header
-(UDataInfo etc.).
-
-Format version 1
-
-A .dat package file contains a simple Table of Contents of item names,
-followed by the items themselves:
-
-1. ToC table
-
-uint32_t count; - number of items
-UDataOffsetTOCEntry entry[count]; - pair of uint32_t values per item:
- uint32_t nameOffset; - offset of the item name
- uint32_t dataOffset; - offset of the item data
-both are byte offsets from the beginning of the data
-
-2. item name strings
-
-All item names are stored as char * strings in one block between the ToC table
-and the data items.
-
-3. data items
-
-The data items are stored following the item names block.
-Each data item is 16-aligned.
-The data items are stored in the sorted order of their names.
-
-Therefore, the top of the name strings block is the offset of the first item,
-the length of the last item is the difference between its offset and
-the .dat file length, and the length of all previous items is the difference
-between its offset and the next one.
-
------------------------------------------------------------------------------ */
-
-/* UDataInfo cf. udata.h */
-static const UDataInfo dataInfo={
- sizeof(UDataInfo),
- 0,
-
- U_IS_BIG_ENDIAN,
- U_CHARSET_FAMILY,
- sizeof(UChar),
- 0,
-
- {0x43, 0x6d, 0x6e, 0x44}, /* dataFormat="CmnD" */
- {1, 0, 0, 0}, /* formatVersion */
- {3, 0, 0, 0} /* dataVersion */
-};
-
-static uint32_t maxSize;
-
-static char stringStore[STRING_STORE_SIZE];
-static uint32_t stringTop=0, basenameTotal=0;
-
-typedef struct {
- char *pathname, *basename;
- uint32_t basenameLength, basenameOffset, fileSize, fileOffset;
-} File;
-
-static File files[MAX_FILE_COUNT];
-static uint32_t fileCount=0;
-
-static char *symPrefix = NULL;
-
-/* prototypes --------------------------------------------------------------- */
-
-static void
-addFile(const char *filename, const char *name, const char *source, UBool sourceTOC, UBool verbose);
-
-static char *
-allocString(uint32_t length);
-
-static int
-compareFiles(const void *file1, const void *file2);
-
-static char *
-pathToFullPath(const char *path, const char *source);
-
-/* map non-tree separator (such as '\') to tree separator ('/') inplace. */
-static void
-fixDirToTreePath(char *s);
-/* -------------------------------------------------------------------------- */
-
-U_CAPI void U_EXPORT2
-createCommonDataFile(const char *destDir, const char *name, const char *entrypointName, const char *type, const char *source, const char *copyRight,
- const char *dataFile, uint32_t max_size, UBool sourceTOC, UBool verbose, char *gencmnFileName) {
- static char buffer[4096];
- char line[512];
- char *s;
- UErrorCode errorCode=U_ZERO_ERROR;
- uint32_t i, fileOffset, basenameOffset, length, nread;
- FileStream *in, *file;
-
- maxSize = max_size;
-
- if (destDir == NULL) {
- destDir = u_getDataDirectory();
- }
- if (name == NULL) {
- name = COMMON_DATA_NAME;
- }
- if (type == NULL) {
- type = DATA_TYPE;
- }
- if (source == NULL) {
- source = ".";
- }
-
- if (dataFile == NULL) {
- in = T_FileStream_stdin();
- } else {
- in = T_FileStream_open(dataFile, "r");
- if(in == NULL) {
- fprintf(stderr, "gencmn: unable to open input file %s\n", dataFile);
- exit(U_FILE_ACCESS_ERROR);
- }
- }
-
- if (verbose) {
- if(sourceTOC) {
- printf("generating %s_%s.c (table of contents source file)\n", name, type);
- } else {
- printf("generating %s.%s (common data file with table of contents)\n", name, type);
- }
- }
-
- /* read the list of files and get their lengths */
- while(T_FileStream_readLine(in, line, sizeof(line))!=NULL) {
- /* remove trailing newline characters */
- s=line;
- while(*s!=0) {
- if(*s=='\r' || *s=='\n') {
- *s=0;
- break;
- }
- ++s;
- }
-
- /* check for comment */
-
- if (*line == '#') {
- continue;
- }
-
- /* add the file */
-#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
- {
- char *t;
- while((t = uprv_strchr(line,U_FILE_ALT_SEP_CHAR))) {
- *t = U_FILE_SEP_CHAR;
- }
- }
-#endif
- addFile(getLongPathname(line), name, source, sourceTOC, verbose);
- }
-
- if(in!=T_FileStream_stdin()) {
- T_FileStream_close(in);
- }
-
- if(fileCount==0) {
- fprintf(stderr, "gencmn: no files listed in %s\n", dataFile == NULL ? "<stdin>" : dataFile);
- return;
- }
-
- /* sort the files by basename */
- qsort(files, fileCount, sizeof(File), compareFiles);
-
- if(!sourceTOC) {
- UNewDataMemory *out;
-
- /* determine the offsets of all basenames and files in this common one */
- basenameOffset=4+8*fileCount;
- fileOffset=(basenameOffset+(basenameTotal+15))&~0xf;
- for(i=0; i<fileCount; ++i) {
- files[i].fileOffset=fileOffset;
- fileOffset+=(files[i].fileSize+15)&~0xf;
- files[i].basenameOffset=basenameOffset;
- basenameOffset+=files[i].basenameLength;
- }
-
- /* create the output file */
- out=udata_create(destDir, type, name,
- &dataInfo,
- copyRight == NULL ? U_COPYRIGHT_STRING : copyRight,
- &errorCode);
- if(U_FAILURE(errorCode)) {
- fprintf(stderr, "gencmn: udata_create(-d %s -n %s -t %s) failed - %s\n",
- destDir, name, type,
- u_errorName(errorCode));
- exit(errorCode);
- }
-
- /* write the table of contents */
- udata_write32(out, fileCount);
- for(i=0; i<fileCount; ++i) {
- udata_write32(out, files[i].basenameOffset);
- udata_write32(out, files[i].fileOffset);
- }
-
- /* write the basenames */
- for(i=0; i<fileCount; ++i) {
- udata_writeString(out, files[i].basename, files[i].basenameLength);
- }
- length=4+8*fileCount+basenameTotal;
-
- /* copy the files */
- for(i=0; i<fileCount; ++i) {
- /* pad to 16-align the next file */
- length&=0xf;
- if(length!=0) {
- udata_writePadding(out, 16-length);
- }
-
- if (verbose) {
- printf("adding %s (%ld byte%s)\n", files[i].pathname, (long)files[i].fileSize, files[i].fileSize == 1 ? "" : "s");
- }
-
- /* copy the next file */
- file=T_FileStream_open(files[i].pathname, "rb");
- if(file==NULL) {
- fprintf(stderr, "gencmn: unable to open listed file %s\n", files[i].pathname);
- exit(U_FILE_ACCESS_ERROR);
- }
- for(nread = 0;;) {
- length=T_FileStream_read(file, buffer, sizeof(buffer));
- if(length <= 0) {
- break;
- }
- nread += length;
- udata_writeBlock(out, buffer, length);
- }
- T_FileStream_close(file);
- length=files[i].fileSize;
-
- if (nread != files[i].fileSize) {
- fprintf(stderr, "gencmn: unable to read %s properly (got %ld/%ld byte%s)\n", files[i].pathname, (long)nread, (long)files[i].fileSize, files[i].fileSize == 1 ? "" : "s");
- exit(U_FILE_ACCESS_ERROR);
- }
- }
-
- /* pad to 16-align the last file (cleaner, avoids growing .dat files in icuswap) */
- length&=0xf;
- if(length!=0) {
- udata_writePadding(out, 16-length);
- }
-
- /* finish */
- udata_finish(out, &errorCode);
- if(U_FAILURE(errorCode)) {
- fprintf(stderr, "gencmn: udata_finish() failed - %s\n", u_errorName(errorCode));
- exit(errorCode);
- }
- } else {
- /* write a .c source file with the table of contents */
- char *filename;
- FileStream *out;
-
- /* create the output filename */
- filename=s=buffer;
- uprv_strcpy(filename, destDir);
- s=filename+uprv_strlen(filename);
- if(s>filename && *(s-1)!=U_FILE_SEP_CHAR) {
- *s++=U_FILE_SEP_CHAR;
- }
- uprv_strcpy(s, name);
- if(*(type)!=0) {
- s+=uprv_strlen(s);
- *s++='_';
- uprv_strcpy(s, type);
- }
- s+=uprv_strlen(s);
- uprv_strcpy(s, ".c");
-
- /* open the output file */
- out=T_FileStream_open(filename, "w");
- if (gencmnFileName != NULL) {
- uprv_strcpy(gencmnFileName, filename);
- }
- if(out==NULL) {
- fprintf(stderr, "gencmn: unable to open .c output file %s\n", filename);
- exit(U_FILE_ACCESS_ERROR);
- }
-
- /* write the source file */
- sprintf(buffer,
- "/*\n"
- " * ICU common data table of contents for %s.%s ,\n"
- " * Automatically generated by icu/source/tools/gencmn/gencmn .\n"
- " */\n\n"
- "#include \"unicode/utypes.h\"\n"
- "#include \"unicode/udata.h\"\n"
- "\n"
- "/* external symbol declarations for data */\n",
- name, type);
- T_FileStream_writeLine(out, buffer);
-
- sprintf(buffer, "extern const char\n %s%s[]", symPrefix?symPrefix:"", files[0].pathname);
- T_FileStream_writeLine(out, buffer);
- for(i=1; i<fileCount; ++i) {
- sprintf(buffer, ",\n %s%s[]", symPrefix?symPrefix:"", files[i].pathname);
- T_FileStream_writeLine(out, buffer);
- }
- T_FileStream_writeLine(out, ";\n\n");
-
- sprintf(
- buffer,
- "U_EXPORT struct {\n"
- " uint16_t headerSize;\n"
- " uint8_t magic1, magic2;\n"
- " UDataInfo info;\n"
- " char padding[%lu];\n"
- " uint32_t count, reserved;\n"
- " struct {\n"
- " const char *name;\n"
- " const void *data;\n"
- " } toc[%lu];\n"
- "} U_EXPORT2 %s_dat = {\n"
- " 32, 0xda, 0x27, {\n"
- " %lu, 0,\n"
- " %u, %u, %u, 0,\n"
- " {0x54, 0x6f, 0x43, 0x50},\n"
- " {1, 0, 0, 0},\n"
- " {0, 0, 0, 0}\n"
- " },\n"
- " \"\", %lu, 0, {\n",
- (unsigned long)32-4-sizeof(UDataInfo),
- (unsigned long)fileCount,
- entrypointName,
- (unsigned long)sizeof(UDataInfo),
- U_IS_BIG_ENDIAN,
- U_CHARSET_FAMILY,
- U_SIZEOF_UCHAR,
- (unsigned long)fileCount
- );
- T_FileStream_writeLine(out, buffer);
-
- sprintf(buffer, " { \"%s\", %s%s }", files[0].basename, symPrefix?symPrefix:"", files[0].pathname);
- T_FileStream_writeLine(out, buffer);
- for(i=1; i<fileCount; ++i) {
- sprintf(buffer, ",\n { \"%s\", %s%s }", files[i].basename, symPrefix?symPrefix:"", files[i].pathname);
- T_FileStream_writeLine(out, buffer);
- }
-
- T_FileStream_writeLine(out, "\n }\n};\n");
- T_FileStream_close(out);
-
- uprv_free(symPrefix);
- }
-}
-
-static void
-addFile(const char *filename, const char *name, const char *source, UBool sourceTOC, UBool verbose) {
- char *s;
- uint32_t length;
- char *fullPath = NULL;
-
- if(fileCount==MAX_FILE_COUNT) {
- fprintf(stderr, "gencmn: too many files, maximum is %d\n", MAX_FILE_COUNT);
- exit(U_BUFFER_OVERFLOW_ERROR);
- }
-
- if(!sourceTOC) {
- FileStream *file;
-
- if(uprv_pathIsAbsolute(filename)) {
- fprintf(stderr, "gencmn: Error: absolute path encountered. Old style paths are not supported. Use relative paths such as 'fur.res' or 'translit%cfur.res'.\n\tBad path: '%s'\n", U_FILE_SEP_CHAR, filename);
- exit(U_ILLEGAL_ARGUMENT_ERROR);
- }
- fullPath = pathToFullPath(filename, source);
-
- /* store the pathname */
- length = (uint32_t)(uprv_strlen(filename) + 1 + uprv_strlen(name) + 1);
- s=allocString(length);
- uprv_strcpy(s, name);
- uprv_strcat(s, U_TREE_ENTRY_SEP_STRING);
- uprv_strcat(s, filename);
-
- /* get the basename */
- fixDirToTreePath(s);
- files[fileCount].basename=s;
- files[fileCount].basenameLength=length;
-
- files[fileCount].pathname=fullPath;
-
- basenameTotal+=length;
-
- /* try to open the file */
- file=T_FileStream_open(fullPath, "rb");
- if(file==NULL) {
- fprintf(stderr, "gencmn: unable to open listed file %s\n", fullPath);
- exit(U_FILE_ACCESS_ERROR);
- }
-
- /* get the file length */
- length=T_FileStream_size(file);
- if(T_FileStream_error(file) || length<=20) {
- fprintf(stderr, "gencmn: unable to get length of listed file %s\n", fullPath);
- exit(U_FILE_ACCESS_ERROR);
- }
-
- T_FileStream_close(file);
-
- /* do not add files that are longer than maxSize */
- if(maxSize && length>maxSize) {
- if (verbose) {
- printf("%s ignored (size %ld > %ld)\n", fullPath, (long)length, (long)maxSize);
- }
- return;
- }
- files[fileCount].fileSize=length;
- } else {
- char *t;
-
- /* get and store the basename */
- /* need to include the package name */
- length = (uint32_t)(uprv_strlen(filename) + 1 + uprv_strlen(name) + 1);
- s=allocString(length);
- uprv_strcpy(s, name);
- uprv_strcat(s, U_TREE_ENTRY_SEP_STRING);
- uprv_strcat(s, filename);
- fixDirToTreePath(s);
- files[fileCount].basename=s;
-
-
- /* turn the basename into an entry point name and store in the pathname field */
- t=files[fileCount].pathname=allocString(length);
- while(--length>0) {
- if(*s=='.' || *s=='-' || *s=='/') {
- *t='_';
- } else {
- *t=*s;
- }
- ++s;
- ++t;
- }
- *t=0;
- }
- ++fileCount;
-}
-
-static char *
-allocString(uint32_t length) {
- uint32_t top=stringTop+length;
- char *p;
-
- if(top>STRING_STORE_SIZE) {
- fprintf(stderr, "gencmn: out of memory\n");
- exit(U_MEMORY_ALLOCATION_ERROR);
- }
- p=stringStore+stringTop;
- stringTop=top;
- return p;
-}
-
-static char *
-pathToFullPath(const char *path, const char *source) {
- int32_t length;
- int32_t newLength;
- char *fullPath;
- int32_t n;
-
- length = (uint32_t)(uprv_strlen(path) + 1);
- newLength = (length + 1 + (int32_t)uprv_strlen(source));
- fullPath = uprv_malloc(newLength);
- if(source != NULL) {
- uprv_strcpy(fullPath, source);
- uprv_strcat(fullPath, U_FILE_SEP_STRING);
- } else {
- fullPath[0] = 0;
- }
- n = (int32_t)uprv_strlen(fullPath);
- uprv_strcat(fullPath, path);
-
-#if (U_FILE_ALT_SEP_CHAR != U_TREE_ENTRY_SEP_CHAR)
-#if (U_FILE_ALT_SEP_CHAR != U_FILE_SEP_CHAR)
- /* replace tree separator (such as '/') with file sep char (such as ':' or '\\') */
- for(;fullPath[n];n++) {
- if(fullPath[n] == U_FILE_ALT_SEP_CHAR) {
- fullPath[n] = U_FILE_SEP_CHAR;
- }
- }
-#endif
-#endif
-#if (U_FILE_SEP_CHAR != U_TREE_ENTRY_SEP_CHAR)
- /* replace tree separator (such as '/') with file sep char (such as ':' or '\\') */
- for(;fullPath[n];n++) {
- if(fullPath[n] == U_TREE_ENTRY_SEP_CHAR) {
- fullPath[n] = U_FILE_SEP_CHAR;
- }
- }
-#endif
- return fullPath;
-}
-
-static int
-compareFiles(const void *file1, const void *file2) {
- /* sort by basename */
- return uprv_strcmp(((File *)file1)->basename, ((File *)file2)->basename);
-}
-
-static void
-fixDirToTreePath(char *s)
-{
-#if (U_FILE_SEP_CHAR != U_TREE_ENTRY_SEP_CHAR) || ((U_FILE_ALT_SEP_CHAR != U_FILE_SEP_CHAR) && (U_FILE_ALT_SEP_CHAR != U_TREE_ENTRY_SEP_CHAR))
- char *t;
-#endif
-#if (U_FILE_SEP_CHAR != U_TREE_ENTRY_SEP_CHAR)
- for(t=s;t=uprv_strchr(t,U_FILE_SEP_CHAR);) {
- *t = U_TREE_ENTRY_SEP_CHAR;
- }
-#endif
-#if (U_FILE_ALT_SEP_CHAR != U_FILE_SEP_CHAR) && (U_FILE_ALT_SEP_CHAR != U_TREE_ENTRY_SEP_CHAR)
- for(t=s;t=uprv_strchr(t,U_FILE_ALT_SEP_CHAR);) {
- *t = U_TREE_ENTRY_SEP_CHAR;
- }
-#endif
-}
+/******************************************************************************
+ * Copyright (C) 2008, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *******************************************************************************
+ */
+#include "unicode/utypes.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "unicode/utypes.h"
+#include "unicode/putil.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "filestrm.h"
+#include "toolutil.h"
+#include "unicode/uclean.h"
+#include "unewdata.h"
+#include "putilimp.h"
+#include "pkg_gencmn.h"
+
+#define STRING_STORE_SIZE 100000
+#define MAX_FILE_COUNT 2000
+
+#define COMMON_DATA_NAME U_ICUDATA_NAME
+#define DATA_TYPE "dat"
+
+/* ICU package data file format (.dat files) ------------------------------- ***
+
+Description of the data format after the usual ICU data file header
+(UDataInfo etc.).
+
+Format version 1
+
+A .dat package file contains a simple Table of Contents of item names,
+followed by the items themselves:
+
+1. ToC table
+
+uint32_t count; - number of items
+UDataOffsetTOCEntry entry[count]; - pair of uint32_t values per item:
+ uint32_t nameOffset; - offset of the item name
+ uint32_t dataOffset; - offset of the item data
+both are byte offsets from the beginning of the data
+
+2. item name strings
+
+All item names are stored as char * strings in one block between the ToC table
+and the data items.
+
+3. data items
+
+The data items are stored following the item names block.
+Each data item is 16-aligned.
+The data items are stored in the sorted order of their names.
+
+Therefore, the top of the name strings block is the offset of the first item,
+the length of the last item is the difference between its offset and
+the .dat file length, and the length of all previous items is the difference
+between its offset and the next one.
+
+----------------------------------------------------------------------------- */
+
+/* UDataInfo cf. udata.h */
+static const UDataInfo dataInfo={
+ sizeof(UDataInfo),
+ 0,
+
+ U_IS_BIG_ENDIAN,
+ U_CHARSET_FAMILY,
+ sizeof(UChar),
+ 0,
+
+ {0x43, 0x6d, 0x6e, 0x44}, /* dataFormat="CmnD" */
+ {1, 0, 0, 0}, /* formatVersion */
+ {3, 0, 0, 0} /* dataVersion */
+};
+
+static uint32_t maxSize;
+
+static char stringStore[STRING_STORE_SIZE];
+static uint32_t stringTop=0, basenameTotal=0;
+
+typedef struct {
+ char *pathname, *basename;
+ uint32_t basenameLength, basenameOffset, fileSize, fileOffset;
+} File;
+
+static File files[MAX_FILE_COUNT];
+static uint32_t fileCount=0;
+
+static char *symPrefix = NULL;
+
+/* prototypes --------------------------------------------------------------- */
+
+static void
+addFile(const char *filename, const char *name, const char *source, UBool sourceTOC, UBool verbose);
+
+static char *
+allocString(uint32_t length);
+
+static int
+compareFiles(const void *file1, const void *file2);
+
+static char *
+pathToFullPath(const char *path, const char *source);
+
+/* map non-tree separator (such as '\') to tree separator ('/') inplace. */
+static void
+fixDirToTreePath(char *s);
+/* -------------------------------------------------------------------------- */
+
+U_CAPI void U_EXPORT2
+createCommonDataFile(const char *destDir, const char *name, const char *entrypointName, const char *type, const char *source, const char *copyRight,
+ const char *dataFile, uint32_t max_size, UBool sourceTOC, UBool verbose, char *gencmnFileName) {
+ static char buffer[4096];
+ char line[512];
+ char *s;
+ UErrorCode errorCode=U_ZERO_ERROR;
+ uint32_t i, fileOffset, basenameOffset, length, nread;
+ FileStream *in, *file;
+
+ maxSize = max_size;
+
+ if (destDir == NULL) {
+ destDir = u_getDataDirectory();
+ }
+ if (name == NULL) {
+ name = COMMON_DATA_NAME;
+ }
+ if (type == NULL) {
+ type = DATA_TYPE;
+ }
+ if (source == NULL) {
+ source = ".";
+ }
+
+ if (dataFile == NULL) {
+ in = T_FileStream_stdin();
+ } else {
+ in = T_FileStream_open(dataFile, "r");
+ if(in == NULL) {
+ fprintf(stderr, "gencmn: unable to open input file %s\n", dataFile);
+ exit(U_FILE_ACCESS_ERROR);
+ }
+ }
+
+ if (verbose) {
+ if(sourceTOC) {
+ printf("generating %s_%s.c (table of contents source file)\n", name, type);
+ } else {
+ printf("generating %s.%s (common data file with table of contents)\n", name, type);
+ }
+ }
+
+ /* read the list of files and get their lengths */
+ while(T_FileStream_readLine(in, line, sizeof(line))!=NULL) {
+ /* remove trailing newline characters */
+ s=line;
+ while(*s!=0) {
+ if(*s=='\r' || *s=='\n') {
+ *s=0;
+ break;
+ }
+ ++s;
+ }
+
+ /* check for comment */
+
+ if (*line == '#') {
+ continue;
+ }
+
+ /* add the file */
+#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
+ {
+ char *t;
+ while((t = uprv_strchr(line,U_FILE_ALT_SEP_CHAR))) {
+ *t = U_FILE_SEP_CHAR;
+ }
+ }
+#endif
+ addFile(getLongPathname(line), name, source, sourceTOC, verbose);
+ }
+
+ if(in!=T_FileStream_stdin()) {
+ T_FileStream_close(in);
+ }
+
+ if(fileCount==0) {
+ fprintf(stderr, "gencmn: no files listed in %s\n", dataFile == NULL ? "<stdin>" : dataFile);
+ return;
+ }
+
+ /* sort the files by basename */
+ qsort(files, fileCount, sizeof(File), compareFiles);
+
+ if(!sourceTOC) {
+ UNewDataMemory *out;
+
+ /* determine the offsets of all basenames and files in this common one */
+ basenameOffset=4+8*fileCount;
+ fileOffset=(basenameOffset+(basenameTotal+15))&~0xf;
+ for(i=0; i<fileCount; ++i) {
+ files[i].fileOffset=fileOffset;
+ fileOffset+=(files[i].fileSize+15)&~0xf;
+ files[i].basenameOffset=basenameOffset;
+ basenameOffset+=files[i].basenameLength;
+ }
+
+ /* create the output file */
+ out=udata_create(destDir, type, name,
+ &dataInfo,
+ copyRight == NULL ? U_COPYRIGHT_STRING : copyRight,
+ &errorCode);
+ if(U_FAILURE(errorCode)) {
+ fprintf(stderr, "gencmn: udata_create(-d %s -n %s -t %s) failed - %s\n",
+ destDir, name, type,
+ u_errorName(errorCode));
+ exit(errorCode);
+ }
+
+ /* write the table of contents */
+ udata_write32(out, fileCount);
+ for(i=0; i<fileCount; ++i) {
+ udata_write32(out, files[i].basenameOffset);
+ udata_write32(out, files[i].fileOffset);
+ }
+
+ /* write the basenames */
+ for(i=0; i<fileCount; ++i) {
+ udata_writeString(out, files[i].basename, files[i].basenameLength);
+ }
+ length=4+8*fileCount+basenameTotal;
+
+ /* copy the files */
+ for(i=0; i<fileCount; ++i) {
+ /* pad to 16-align the next file */
+ length&=0xf;
+ if(length!=0) {
+ udata_writePadding(out, 16-length);
+ }
+
+ if (verbose) {
+ printf("adding %s (%ld byte%s)\n", files[i].pathname, (long)files[i].fileSize, files[i].fileSize == 1 ? "" : "s");
+ }
+
+ /* copy the next file */
+ file=T_FileStream_open(files[i].pathname, "rb");
+ if(file==NULL) {
+ fprintf(stderr, "gencmn: unable to open listed file %s\n", files[i].pathname);
+ exit(U_FILE_ACCESS_ERROR);
+ }
+ for(nread = 0;;) {
+ length=T_FileStream_read(file, buffer, sizeof(buffer));
+ if(length <= 0) {
+ break;
+ }
+ nread += length;
+ udata_writeBlock(out, buffer, length);
+ }
+ T_FileStream_close(file);
+ length=files[i].fileSize;
+
+ if (nread != files[i].fileSize) {
+ fprintf(stderr, "gencmn: unable to read %s properly (got %ld/%ld byte%s)\n", files[i].pathname, (long)nread, (long)files[i].fileSize, files[i].fileSize == 1 ? "" : "s");
+ exit(U_FILE_ACCESS_ERROR);
+ }
+ }
+
+ /* pad to 16-align the last file (cleaner, avoids growing .dat files in icuswap) */
+ length&=0xf;
+ if(length!=0) {
+ udata_writePadding(out, 16-length);
+ }
+
+ /* finish */
+ udata_finish(out, &errorCode);
+ if(U_FAILURE(errorCode)) {
+ fprintf(stderr, "gencmn: udata_finish() failed - %s\n", u_errorName(errorCode));
+ exit(errorCode);
+ }
+ } else {
+ /* write a .c source file with the table of contents */
+ char *filename;
+ FileStream *out;
+
+ /* create the output filename */
+ filename=s=buffer;
+ uprv_strcpy(filename, destDir);
+ s=filename+uprv_strlen(filename);
+ if(s>filename && *(s-1)!=U_FILE_SEP_CHAR) {
+ *s++=U_FILE_SEP_CHAR;
+ }
+ uprv_strcpy(s, name);
+ if(*(type)!=0) {
+ s+=uprv_strlen(s);
+ *s++='_';
+ uprv_strcpy(s, type);
+ }
+ s+=uprv_strlen(s);
+ uprv_strcpy(s, ".c");
+
+ /* open the output file */
+ out=T_FileStream_open(filename, "w");
+ if (gencmnFileName != NULL) {
+ uprv_strcpy(gencmnFileName, filename);
+ }
+ if(out==NULL) {
+ fprintf(stderr, "gencmn: unable to open .c output file %s\n", filename);
+ exit(U_FILE_ACCESS_ERROR);
+ }
+
+ /* write the source file */
+ sprintf(buffer,
+ "/*\n"
+ " * ICU common data table of contents for %s.%s ,\n"
+ " * Automatically generated by icu/source/tools/gencmn/gencmn .\n"
+ " */\n\n"
+ "#include \"unicode/utypes.h\"\n"
+ "#include \"unicode/udata.h\"\n"
+ "\n"
+ "/* external symbol declarations for data */\n",
+ name, type);
+ T_FileStream_writeLine(out, buffer);
+
+ sprintf(buffer, "extern const char\n %s%s[]", symPrefix?symPrefix:"", files[0].pathname);
+ T_FileStream_writeLine(out, buffer);
+ for(i=1; i<fileCount; ++i) {
+ sprintf(buffer, ",\n %s%s[]", symPrefix?symPrefix:"", files[i].pathname);
+ T_FileStream_writeLine(out, buffer);
+ }
+ T_FileStream_writeLine(out, ";\n\n");
+
+ sprintf(
+ buffer,
+ "U_EXPORT struct {\n"
+ " uint16_t headerSize;\n"
+ " uint8_t magic1, magic2;\n"
+ " UDataInfo info;\n"
+ " char padding[%lu];\n"
+ " uint32_t count, reserved;\n"
+ " struct {\n"
+ " const char *name;\n"
+ " const void *data;\n"
+ " } toc[%lu];\n"
+ "} U_EXPORT2 %s_dat = {\n"
+ " 32, 0xda, 0x27, {\n"
+ " %lu, 0,\n"
+ " %u, %u, %u, 0,\n"
+ " {0x54, 0x6f, 0x43, 0x50},\n"
+ " {1, 0, 0, 0},\n"
+ " {0, 0, 0, 0}\n"
+ " },\n"
+ " \"\", %lu, 0, {\n",
+ (unsigned long)32-4-sizeof(UDataInfo),
+ (unsigned long)fileCount,
+ entrypointName,
+ (unsigned long)sizeof(UDataInfo),
+ U_IS_BIG_ENDIAN,
+ U_CHARSET_FAMILY,
+ U_SIZEOF_UCHAR,
+ (unsigned long)fileCount
+ );
+ T_FileStream_writeLine(out, buffer);
+
+ sprintf(buffer, " { \"%s\", %s%s }", files[0].basename, symPrefix?symPrefix:"", files[0].pathname);
+ T_FileStream_writeLine(out, buffer);
+ for(i=1; i<fileCount; ++i) {
+ sprintf(buffer, ",\n { \"%s\", %s%s }", files[i].basename, symPrefix?symPrefix:"", files[i].pathname);
+ T_FileStream_writeLine(out, buffer);
+ }
+
+ T_FileStream_writeLine(out, "\n }\n};\n");
+ T_FileStream_close(out);
+
+ uprv_free(symPrefix);
+ }
+}
+
+static void
+addFile(const char *filename, const char *name, const char *source, UBool sourceTOC, UBool verbose) {
+ char *s;
+ uint32_t length;
+ char *fullPath = NULL;
+
+ if(fileCount==MAX_FILE_COUNT) {
+ fprintf(stderr, "gencmn: too many files, maximum is %d\n", MAX_FILE_COUNT);
+ exit(U_BUFFER_OVERFLOW_ERROR);
+ }
+
+ if(!sourceTOC) {
+ FileStream *file;
+
+ if(uprv_pathIsAbsolute(filename)) {
+ fprintf(stderr, "gencmn: Error: absolute path encountered. Old style paths are not supported. Use relative paths such as 'fur.res' or 'translit%cfur.res'.\n\tBad path: '%s'\n", U_FILE_SEP_CHAR, filename);
+ exit(U_ILLEGAL_ARGUMENT_ERROR);
+ }
+ fullPath = pathToFullPath(filename, source);
+
+ /* store the pathname */
+ length = (uint32_t)(uprv_strlen(filename) + 1 + uprv_strlen(name) + 1);
+ s=allocString(length);
+ uprv_strcpy(s, name);
+ uprv_strcat(s, U_TREE_ENTRY_SEP_STRING);
+ uprv_strcat(s, filename);
+
+ /* get the basename */
+ fixDirToTreePath(s);
+ files[fileCount].basename=s;
+ files[fileCount].basenameLength=length;
+
+ files[fileCount].pathname=fullPath;
+
+ basenameTotal+=length;
+
+ /* try to open the file */
+ file=T_FileStream_open(fullPath, "rb");
+ if(file==NULL) {
+ fprintf(stderr, "gencmn: unable to open listed file %s\n", fullPath);
+ exit(U_FILE_ACCESS_ERROR);
+ }
+
+ /* get the file length */
+ length=T_FileStream_size(file);
+ if(T_FileStream_error(file) || length<=20) {
+ fprintf(stderr, "gencmn: unable to get length of listed file %s\n", fullPath);
+ exit(U_FILE_ACCESS_ERROR);
+ }
+
+ T_FileStream_close(file);
+
+ /* do not add files that are longer than maxSize */
+ if(maxSize && length>maxSize) {
+ if (verbose) {
+ printf("%s ignored (size %ld > %ld)\n", fullPath, (long)length, (long)maxSize);
+ }
+ return;
+ }
+ files[fileCount].fileSize=length;
+ } else {
+ char *t;
+
+ /* get and store the basename */
+ /* need to include the package name */
+ length = (uint32_t)(uprv_strlen(filename) + 1 + uprv_strlen(name) + 1);
+ s=allocString(length);
+ uprv_strcpy(s, name);
+ uprv_strcat(s, U_TREE_ENTRY_SEP_STRING);
+ uprv_strcat(s, filename);
+ fixDirToTreePath(s);
+ files[fileCount].basename=s;
+
+
+ /* turn the basename into an entry point name and store in the pathname field */
+ t=files[fileCount].pathname=allocString(length);
+ while(--length>0) {
+ if(*s=='.' || *s=='-' || *s=='/') {
+ *t='_';
+ } else {
+ *t=*s;
+ }
+ ++s;
+ ++t;
+ }
+ *t=0;
+ }
+ ++fileCount;
+}
+
+static char *
+allocString(uint32_t length) {
+ uint32_t top=stringTop+length;
+ char *p;
+
+ if(top>STRING_STORE_SIZE) {
+ fprintf(stderr, "gencmn: out of memory\n");
+ exit(U_MEMORY_ALLOCATION_ERROR);
+ }
+ p=stringStore+stringTop;
+ stringTop=top;
+ return p;
+}
+
+static char *
+pathToFullPath(const char *path, const char *source) {
+ int32_t length;
+ int32_t newLength;
+ char *fullPath;
+ int32_t n;
+
+ length = (uint32_t)(uprv_strlen(path) + 1);
+ newLength = (length + 1 + (int32_t)uprv_strlen(source));
+ fullPath = uprv_malloc(newLength);
+ if(source != NULL) {
+ uprv_strcpy(fullPath, source);
+ uprv_strcat(fullPath, U_FILE_SEP_STRING);
+ } else {
+ fullPath[0] = 0;
+ }
+ n = (int32_t)uprv_strlen(fullPath);
+ uprv_strcat(fullPath, path);
+
+#if (U_FILE_ALT_SEP_CHAR != U_TREE_ENTRY_SEP_CHAR)
+#if (U_FILE_ALT_SEP_CHAR != U_FILE_SEP_CHAR)
+ /* replace tree separator (such as '/') with file sep char (such as ':' or '\\') */
+ for(;fullPath[n];n++) {
+ if(fullPath[n] == U_FILE_ALT_SEP_CHAR) {
+ fullPath[n] = U_FILE_SEP_CHAR;
+ }
+ }
+#endif
+#endif
+#if (U_FILE_SEP_CHAR != U_TREE_ENTRY_SEP_CHAR)
+ /* replace tree separator (such as '/') with file sep char (such as ':' or '\\') */
+ for(;fullPath[n];n++) {
+ if(fullPath[n] == U_TREE_ENTRY_SEP_CHAR) {
+ fullPath[n] = U_FILE_SEP_CHAR;
+ }
+ }
+#endif
+ return fullPath;
+}
+
+static int
+compareFiles(const void *file1, const void *file2) {
+ /* sort by basename */
+ return uprv_strcmp(((File *)file1)->basename, ((File *)file2)->basename);
+}
+
+static void
+fixDirToTreePath(char *s)
+{
+#if (U_FILE_SEP_CHAR != U_TREE_ENTRY_SEP_CHAR) || ((U_FILE_ALT_SEP_CHAR != U_FILE_SEP_CHAR) && (U_FILE_ALT_SEP_CHAR != U_TREE_ENTRY_SEP_CHAR))
+ char *t;
+#endif
+#if (U_FILE_SEP_CHAR != U_TREE_ENTRY_SEP_CHAR)
+ for(t=s;t=uprv_strchr(t,U_FILE_SEP_CHAR);) {
+ *t = U_TREE_ENTRY_SEP_CHAR;
+ }
+#endif
+#if (U_FILE_ALT_SEP_CHAR != U_FILE_SEP_CHAR) && (U_FILE_ALT_SEP_CHAR != U_TREE_ENTRY_SEP_CHAR)
+ for(t=s;t=uprv_strchr(t,U_FILE_ALT_SEP_CHAR);) {
+ *t = U_TREE_ENTRY_SEP_CHAR;
+ }
+#endif
+}
Modified: trunk/source/tools/toolutil/pkg_gencmn.h
===================================================================
--- trunk/source/tools/toolutil/pkg_gencmn.h 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/tools/toolutil/pkg_gencmn.h 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,16 +1,16 @@
-/******************************************************************************
- * Copyright (C) 2008, International Business Machines
- * Corporation and others. All Rights Reserved.
- *******************************************************************************
- */
-
-#ifndef __PKG_GENCMN_H__
-#define __PKG_GENCMN_H__
-
-#include "unicode/utypes.h"
-
-U_CAPI void U_EXPORT2
-createCommonDataFile(const char *destDir, const char *name, const char *entrypointName, const char *type, const char *source, const char *copyRight,
- const char *dataFile, uint32_t max_size, UBool sourceTOC, UBool verbose, char *gencmnFileName);
-
-#endif
+/******************************************************************************
+ * Copyright (C) 2008, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *******************************************************************************
+ */
+
+#ifndef __PKG_GENCMN_H__
+#define __PKG_GENCMN_H__
+
+#include "unicode/utypes.h"
+
+U_CAPI void U_EXPORT2
+createCommonDataFile(const char *destDir, const char *name, const char *entrypointName, const char *type, const char *source, const char *copyRight,
+ const char *dataFile, uint32_t max_size, UBool sourceTOC, UBool verbose, char *gencmnFileName);
+
+#endif
Modified: trunk/source/tools/toolutil/pkg_icu.cpp
===================================================================
--- trunk/source/tools/toolutil/pkg_icu.cpp 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/tools/toolutil/pkg_icu.cpp 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,178 +1,178 @@
-/******************************************************************************
- * Copyright (C) 2008-2009, International Business Machines
- * Corporation and others. All Rights Reserved.
- *******************************************************************************
- */
-#include "unicode/utypes.h"
-#include "unicode/putil.h"
-#include "cstring.h"
-#include "toolutil.h"
-#include "uoptions.h"
-#include "uparse.h"
-#include "package.h"
-#include "pkg_icu.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-
-#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
-
-// read a file list -------------------------------------------------------- ***
-
-static const struct {
- const char *suffix;
- int32_t length;
-} listFileSuffixes[]={
- { ".txt", 4 },
- { ".lst", 4 },
- { ".tmp", 4 }
-};
-
-/* check for multiple text file suffixes to see if this list name is a text file name */
-static UBool
-isListTextFile(const char *listname) {
- const char *listNameEnd=strchr(listname, 0);
- const char *suffix;
- int32_t i, length;
- for(i=0; i<LENGTHOF(listFileSuffixes); ++i) {
- suffix=listFileSuffixes[i].suffix;
- length=listFileSuffixes[i].length;
- if((listNameEnd-listname)>length && 0==memcmp(listNameEnd-length, suffix, length)) {
- return TRUE;
- }
- }
- return FALSE;
-}
-
-/*
- * Read a file list.
- * If the listname ends with ".txt", then read the list file
- * (in the system/ invariant charset).
- * If the listname ends with ".dat", then read the ICU .dat package file.
- * Otherwise, read the file itself as a single-item list.
- */
-U_CAPI Package * U_EXPORT2
-readList(const char *filesPath, const char *listname, UBool readContents) {
- Package *listPkg;
- FILE *file;
- const char *listNameEnd;
-
- if(listname==NULL || listname[0]==0) {
- fprintf(stderr, "missing list file\n");
- return NULL;
- }
-
- listPkg=new Package();
- if(listPkg==NULL) {
- fprintf(stderr, "icupkg: not enough memory\n");
- exit(U_MEMORY_ALLOCATION_ERROR);
- }
-
- listNameEnd=strchr(listname, 0);
- if(isListTextFile(listname)) {
- // read the list file
- char line[1024];
- char *end;
- const char *start;
-
- file=fopen(listname, "r");
- if(file==NULL) {
- fprintf(stderr, "icupkg: unable to open list file \"%s\"\n", listname);
- delete listPkg;
- exit(U_FILE_ACCESS_ERROR);
- }
-
- while(fgets(line, sizeof(line), file)) {
- // remove comments
- end=strchr(line, '#');
- if(end!=NULL) {
- *end=0;
- } else {
- // remove trailing CR LF
- end=strchr(line, 0);
- while(line<end && (*(end-1)=='\r' || *(end-1)=='\n')) {
- *--end=0;
- }
- }
-
- // check first non-whitespace character and
- // skip empty lines and
- // skip lines starting with reserved characters
- start=u_skipWhitespace(line);
- if(*start==0 || NULL!=strchr(U_PKG_RESERVED_CHARS, *start)) {
- continue;
- }
-
- // take whitespace-separated items from the line
- for(;;) {
- // find whitespace after the item or the end of the line
- for(end=(char *)start; *end!=0 && *end!=' ' && *end!='\t'; ++end) {}
- if(*end==0) {
- // this item is the last one on the line
- end=NULL;
- } else {
- // the item is terminated by whitespace, terminate it with NUL
- *end=0;
- }
- if(readContents) {
- listPkg->addFile(filesPath, start);
- } else {
- listPkg->addItem(start);
- }
-
- // find the start of the next item or exit the loop
- if(end==NULL || *(start=u_skipWhitespace(end+1))==0) {
- break;
- }
- }
- }
- fclose(file);
- } else if((listNameEnd-listname)>4 && 0==memcmp(listNameEnd-4, ".dat", 4)) {
- // read the ICU .dat package
- listPkg->readPackage(listname);
- } else {
- // list the single file itself
- if(readContents) {
- listPkg->addFile(filesPath, listname);
- } else {
- listPkg->addItem(listname);
- }
- }
-
- return listPkg;
-}
-
-U_CAPI int U_EXPORT2
-writePackageDatFile(const char *outFilename, const char *outComment, const char *sourcePath, const char *addList, Package *pkg, char outType) {
- Package *addListPkg = NULL;
- UBool pkgDelete = FALSE;
-
- if (pkg == NULL) {
- pkg = new Package;
- if(pkg == NULL) {
- fprintf(stderr, "icupkg: not enough memory\n");
- return U_MEMORY_ALLOCATION_ERROR;
- }
-
- addListPkg = readList(sourcePath, addList, TRUE);
- if(addListPkg != NULL) {
- pkg->addItems(*addListPkg);
- } else {
- return U_ILLEGAL_ARGUMENT_ERROR;
- }
-
- pkgDelete = TRUE;
- }
-
- pkg->writePackage(outFilename, outType, outComment);
-
- if (pkgDelete) {
- delete pkg;
- delete addListPkg;
- }
-
- return 0;
-}
-
+/******************************************************************************
+ * Copyright (C) 2008-2009, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *******************************************************************************
+ */
+#include "unicode/utypes.h"
+#include "unicode/putil.h"
+#include "cstring.h"
+#include "toolutil.h"
+#include "uoptions.h"
+#include "uparse.h"
+#include "package.h"
+#include "pkg_icu.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+// read a file list -------------------------------------------------------- ***
+
+static const struct {
+ const char *suffix;
+ int32_t length;
+} listFileSuffixes[]={
+ { ".txt", 4 },
+ { ".lst", 4 },
+ { ".tmp", 4 }
+};
+
+/* check for multiple text file suffixes to see if this list name is a text file name */
+static UBool
+isListTextFile(const char *listname) {
+ const char *listNameEnd=strchr(listname, 0);
+ const char *suffix;
+ int32_t i, length;
+ for(i=0; i<LENGTHOF(listFileSuffixes); ++i) {
+ suffix=listFileSuffixes[i].suffix;
+ length=listFileSuffixes[i].length;
+ if((listNameEnd-listname)>length && 0==memcmp(listNameEnd-length, suffix, length)) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Read a file list.
+ * If the listname ends with ".txt", then read the list file
+ * (in the system/ invariant charset).
+ * If the listname ends with ".dat", then read the ICU .dat package file.
+ * Otherwise, read the file itself as a single-item list.
+ */
+U_CAPI Package * U_EXPORT2
+readList(const char *filesPath, const char *listname, UBool readContents) {
+ Package *listPkg;
+ FILE *file;
+ const char *listNameEnd;
+
+ if(listname==NULL || listname[0]==0) {
+ fprintf(stderr, "missing list file\n");
+ return NULL;
+ }
+
+ listPkg=new Package();
+ if(listPkg==NULL) {
+ fprintf(stderr, "icupkg: not enough memory\n");
+ exit(U_MEMORY_ALLOCATION_ERROR);
+ }
+
+ listNameEnd=strchr(listname, 0);
+ if(isListTextFile(listname)) {
+ // read the list file
+ char line[1024];
+ char *end;
+ const char *start;
+
+ file=fopen(listname, "r");
+ if(file==NULL) {
+ fprintf(stderr, "icupkg: unable to open list file \"%s\"\n", listname);
+ delete listPkg;
+ exit(U_FILE_ACCESS_ERROR);
+ }
+
+ while(fgets(line, sizeof(line), file)) {
+ // remove comments
+ end=strchr(line, '#');
+ if(end!=NULL) {
+ *end=0;
+ } else {
+ // remove trailing CR LF
+ end=strchr(line, 0);
+ while(line<end && (*(end-1)=='\r' || *(end-1)=='\n')) {
+ *--end=0;
+ }
+ }
+
+ // check first non-whitespace character and
+ // skip empty lines and
+ // skip lines starting with reserved characters
+ start=u_skipWhitespace(line);
+ if(*start==0 || NULL!=strchr(U_PKG_RESERVED_CHARS, *start)) {
+ continue;
+ }
+
+ // take whitespace-separated items from the line
+ for(;;) {
+ // find whitespace after the item or the end of the line
+ for(end=(char *)start; *end!=0 && *end!=' ' && *end!='\t'; ++end) {}
+ if(*end==0) {
+ // this item is the last one on the line
+ end=NULL;
+ } else {
+ // the item is terminated by whitespace, terminate it with NUL
+ *end=0;
+ }
+ if(readContents) {
+ listPkg->addFile(filesPath, start);
+ } else {
+ listPkg->addItem(start);
+ }
+
+ // find the start of the next item or exit the loop
+ if(end==NULL || *(start=u_skipWhitespace(end+1))==0) {
+ break;
+ }
+ }
+ }
+ fclose(file);
+ } else if((listNameEnd-listname)>4 && 0==memcmp(listNameEnd-4, ".dat", 4)) {
+ // read the ICU .dat package
+ listPkg->readPackage(listname);
+ } else {
+ // list the single file itself
+ if(readContents) {
+ listPkg->addFile(filesPath, listname);
+ } else {
+ listPkg->addItem(listname);
+ }
+ }
+
+ return listPkg;
+}
+
+U_CAPI int U_EXPORT2
+writePackageDatFile(const char *outFilename, const char *outComment, const char *sourcePath, const char *addList, Package *pkg, char outType) {
+ Package *addListPkg = NULL;
+ UBool pkgDelete = FALSE;
+
+ if (pkg == NULL) {
+ pkg = new Package;
+ if(pkg == NULL) {
+ fprintf(stderr, "icupkg: not enough memory\n");
+ return U_MEMORY_ALLOCATION_ERROR;
+ }
+
+ addListPkg = readList(sourcePath, addList, TRUE);
+ if(addListPkg != NULL) {
+ pkg->addItems(*addListPkg);
+ } else {
+ return U_ILLEGAL_ARGUMENT_ERROR;
+ }
+
+ pkgDelete = TRUE;
+ }
+
+ pkg->writePackage(outFilename, outType, outComment);
+
+ if (pkgDelete) {
+ delete pkg;
+ delete addListPkg;
+ }
+
+ return 0;
+}
+
Modified: trunk/source/tools/toolutil/pkg_icu.h
===================================================================
--- trunk/source/tools/toolutil/pkg_icu.h 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/tools/toolutil/pkg_icu.h 2009-07-02 19:32:00 UTC (rev 214)
@@ -1,22 +1,22 @@
-/******************************************************************************
- * Copyright (C) 2008-2009, International Business Machines
- * Corporation and others. All Rights Reserved.
- *******************************************************************************
- */
-
-#ifndef __PKG_ICU_H__
-#define __PKG_ICU_H__
-
-#include "unicode/utypes.h"
-
-#define U_PKG_RESERVED_CHARS "\"%&'()*+,-./:;<=>?_"
-
-U_CAPI int U_EXPORT2
-writePackageDatFile(const char *outFilename, const char *outComment,
- const char *sourcePath, const char *addList, Package *pkg,
- char outType);
-
-U_CAPI Package * U_EXPORT2
-readList(const char *filesPath, const char *listname, UBool readContents);
-
-#endif
+/******************************************************************************
+ * Copyright (C) 2008-2009, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *******************************************************************************
+ */
+
+#ifndef __PKG_ICU_H__
+#define __PKG_ICU_H__
+
+#include "unicode/utypes.h"
+
+#define U_PKG_RESERVED_CHARS "\"%&'()*+,-./:;<=>?_"
+
+U_CAPI int U_EXPORT2
+writePackageDatFile(const char *outFilename, const char *outComment,
+ const char *sourcePath, const char *addList, Package *pkg,
+ char outType);
+
+U_CAPI Package * U_EXPORT2
+readList(const char *filesPath, const char *listname, UBool readContents);
+
+#endif
Modified: trunk/source/tools/toolutil/toolutil.c
===================================================================
--- trunk/source/tools/toolutil/toolutil.c 2009-07-02 19:31:11 UTC (rev 213)
+++ trunk/source/tools/toolutil/toolutil.c 2009-07-02 19:32:00 UTC (rev 214)
@@ -66,7 +66,7 @@
getLongPathname(const char *pathname) {
#ifdef U_WINDOWS
/* anticipate problems with "short" pathnames */
- static WIN32_FIND_DATA info;
+ static WIN32_FIND_DATAA info;
HANDLE file=FindFirstFileA(pathname, &info);
if(file!=INVALID_HANDLE_VALUE) {
if(info.cAlternateFileName[0]!=0) {
More information about the sword-cvs
mailing list