diff --git a/gnu/local.mk b/gnu/local.mk index bbf13bf6143..e2498d58f0b 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -1610,15 +1610,24 @@ dist_patch_DATA = \ %D%/packages/patches/icedove-observer-fix.patch \ %D%/packages/patches/icedtea-7-hotspot-aarch64-use-c++98.patch \ %D%/packages/patches/icedtea-7-hotspot-pointer-comparison.patch \ - %D%/packages/patches/icu4c-icu-22132-fix-vtimezone.patch \ - %D%/packages/patches/icu4c-20548-dateinterval-timezone.patch \ - %D%/packages/patches/icu4c-22132-standardize-vtzone-output.patch \ - %D%/packages/patches/icu4c-23069-rosh-hashanah-postponement.patch \ - %D%/packages/patches/icu4c-dayperiod-fractional-seconds.patch \ - %D%/packages/patches/icu4c-double-conversion.patch \ - %D%/packages/patches/icu4c-dtitvfmt-adopt-calendar.patch \ + %D%/packages/patches/icu4c-20548-dateinterval-timezone.patch \ + %D%/packages/patches/icu4c-22132-standardize-vtzone-output.patch \ + %D%/packages/patches/icu4c-23069-rosh-hashanah-postponement.patch \ + %D%/packages/patches/icu4c-78-double-conversion.patch \ + %D%/packages/patches/icu4c-bug-1706949-wasi-workaround.patch \ + %D%/packages/patches/icu4c-bug-1790071-ICU-22132-standardize-vtzone-output.patch \ + %D%/packages/patches/icu4c-bug-1856290-ICU-20548-dateinterval-timezone.patch \ + %D%/packages/patches/icu4c-bug-1954138-dtitvfmt-adopt-calendar.patch \ + %D%/packages/patches/icu4c-bug-1972781-chinese-based-calendar.patch \ + %D%/packages/patches/icu4c-bug-2000225-ICU-23264-increase-measure-unit-capacity.patch \ + %D%/packages/patches/icu4c-bug-2002735-ICU-23277-coptic-single-era.patch \ + %D%/packages/patches/icu4c-dayperiod-fractional-seconds.patch \ + %D%/packages/patches/icu4c-double-conversion.patch \ + %D%/packages/patches/icu4c-dtitvfmt-adopt-calendar.patch \ %D%/packages/patches/icu4c-fix-TestHebrewCalendarInTemporalLeapYear.patch \ - %D%/packages/patches/icu4c-wasi-workaround.patch \ + %D%/packages/patches/icu4c-icu-22132-fix-vtimezone.patch \ + %D%/packages/patches/icu4c-suppress-warnings.patch \ + %D%/packages/patches/icu4c-wasi-workaround.patch \ %D%/packages/patches/id3lib-CVE-2007-4460.patch \ %D%/packages/patches/id3lib-UTF16-writing-bug.patch \ %D%/packages/patches/ilmbase-fix-tests.patch \ diff --git a/gnu/packages/icu4c.scm b/gnu/packages/icu4c.scm index 492812cc12f..eaf1bd17808 100644 --- a/gnu/packages/icu4c.scm +++ b/gnu/packages/icu4c.scm @@ -52,6 +52,12 @@ (string-map (lambda (x) (if (char=? x #\.) #\_ x)) version) "-src.tgz")) +;; The URI format has changed starting with 78.1. +(define (icu4c-uri->=78 version) + (string-append + "https://github.com/unicode-org/icu/releases/download/release-" + version "/icu4c-" version "-sources.tgz")) + (define-public icu4c-73 (package (name "icu4c") @@ -201,6 +207,27 @@ C/C++ part.") "icu4c-dtitvfmt-adopt-calendar.patch" "icu4c-wasi-workaround.patch")))))) +(define-public icu4c-78 + (package + (inherit icu4c-77) + (name "icu4c") + (version "78.2") + (source + (origin + (inherit (package-source icu4c-77)) + (uri (icu4c-uri->=78 version)) + (sha256 (base32 "0dfzi4yf0wmng1866y2yd22cj1lrnzmx5qihjqh4npa3bixni69y")) + (patches + (search-patches + "icu4c-bug-1706949-wasi-workaround.patch" + "icu4c-bug-1790071-ICU-22132-standardize-vtzone-output.patch" + "icu4c-bug-1856290-ICU-20548-dateinterval-timezone.patch" + "icu4c-bug-1954138-dtitvfmt-adopt-calendar.patch" + "icu4c-bug-1972781-chinese-based-calendar.patch" + "icu4c-bug-2000225-ICU-23264-increase-measure-unit-capacity.patch" + "icu4c-78-double-conversion.patch" + "icu4c-suppress-warnings.patch")))))) + (define-public icu4c-build-root (package (inherit icu4c) diff --git a/gnu/packages/patches/icu4c-78-double-conversion.patch b/gnu/packages/patches/icu4c-78-double-conversion.patch new file mode 100644 index 00000000000..c4c54ec97b0 --- /dev/null +++ b/gnu/packages/patches/icu4c-78-double-conversion.patch @@ -0,0 +1,198 @@ +diff --git a/source/i18n/measunit_extra.cpp b/source/i18n/measunit_extra.cpp +--- a/source/i18n/measunit_extra.cpp ++++ b/source/i18n/measunit_extra.cpp +@@ -10,17 +10,21 @@ + + // Allow implicit conversion from char16_t* to UnicodeString for this file: + // Helpful in toString methods and elsewhere. + #define UNISTR_FROM_STRING_EXPLICIT + + #include "charstr.h" + #include "cmemory.h" + #include "cstring.h" ++#ifdef JS_HAS_INTL_API ++#include "double-conversion/string-to-double.h" ++#else + #include "double-conversion-string-to-double.h" ++#endif + #include "measunit_impl.h" + #include "resource.h" + #include "uarrsort.h" + #include "uassert.h" + #include "ucln_in.h" + #include "umutex.h" + #include "unicode/bytestrie.h" + #include "unicode/bytestriebuilder.h" +@@ -33,17 +37,21 @@ + #include "util.h" + #include + #include + U_NAMESPACE_BEGIN + + + namespace { + ++#ifdef JS_HAS_INTL_API ++using double_conversion::StringToDoubleConverter; ++#else + using icu::double_conversion::StringToDoubleConverter; ++#endif + + // TODO: Propose a new error code for this? + constexpr UErrorCode kUnitIdentifierSyntaxError = U_ILLEGAL_ARGUMENT_ERROR; + + // Trie value offset for SI or binary prefixes. This is big enough to ensure we only + // insert positive integers into the trie. + constexpr int32_t kPrefixOffset = 64; + static_assert(kPrefixOffset + UMEASURE_PREFIX_INTERNAL_MIN_BIN > 0, +diff --git a/source/i18n/number_decimalquantity.cpp b/source/i18n/number_decimalquantity.cpp +--- a/source/i18n/number_decimalquantity.cpp ++++ b/source/i18n/number_decimalquantity.cpp +@@ -11,28 +11,37 @@ + #include + + #include "unicode/plurrule.h" + #include "cmemory.h" + #include "number_decnum.h" + #include "putilimp.h" + #include "number_decimalquantity.h" + #include "number_roundingutils.h" ++#ifdef JS_HAS_INTL_API ++#include "double-conversion/double-conversion.h" ++#else + #include "double-conversion.h" ++#endif + #include "charstr.h" + #include "number_utils.h" + #include "uassert.h" + #include "util.h" + + using namespace icu; + using namespace icu::number; + using namespace icu::number::impl; + ++#ifdef JS_HAS_INTL_API ++using double_conversion::DoubleToStringConverter; ++using double_conversion::StringToDoubleConverter; ++#else + using icu::double_conversion::DoubleToStringConverter; + using icu::double_conversion::StringToDoubleConverter; ++#endif + + namespace { + + int8_t NEGATIVE_FLAG = 1; + int8_t INFINITY_FLAG = 2; + int8_t NAN_FLAG = 4; + + /** Helper function for safe subtraction (no overflow). */ +diff --git a/source/i18n/number_rounding.cpp b/source/i18n/number_rounding.cpp +--- a/source/i18n/number_rounding.cpp ++++ b/source/i18n/number_rounding.cpp +@@ -5,17 +5,21 @@ + + #if !UCONFIG_NO_FORMATTING + + #include "charstr.h" + #include "uassert.h" + #include "unicode/numberformatter.h" + #include "number_types.h" + #include "number_decimalquantity.h" ++#ifdef JS_HAS_INTL_API ++#include "double-conversion/double-conversion.h" ++#else + #include "double-conversion.h" ++#endif + #include "number_roundingutils.h" + #include "number_skeletons.h" + #include "number_decnum.h" + #include "putilimp.h" + #include "string_segment.h" + + using namespace icu; + using namespace icu::number; +diff --git a/source/i18n/number_utils.cpp b/source/i18n/number_utils.cpp +--- a/source/i18n/number_utils.cpp ++++ b/source/i18n/number_utils.cpp +@@ -12,26 +12,34 @@ + #include + #include + #include "number_decnum.h" + #include "number_types.h" + #include "number_utils.h" + #include "charstr.h" + #include "decContext.h" + #include "decNumber.h" ++#ifdef JS_HAS_INTL_API ++#include "double-conversion/double-conversion.h" ++#else + #include "double-conversion.h" ++#endif + #include "fphdlimp.h" + #include "uresimp.h" + #include "ureslocs.h" + + using namespace icu; + using namespace icu::number; + using namespace icu::number::impl; + ++#ifdef JS_HAS_INTL_API ++using double_conversion::DoubleToStringConverter; ++#else + using icu::double_conversion::DoubleToStringConverter; ++#endif + + + namespace { + + const char16_t* + doGetPattern(UResourceBundle* res, const char* nsName, const char* patternKey, UErrorCode& publicStatus, + UErrorCode& localStatus) { + // Construct the path into the resource bundle +diff --git a/source/i18n/units_converter.cpp b/source/i18n/units_converter.cpp +--- a/source/i18n/units_converter.cpp ++++ b/source/i18n/units_converter.cpp +@@ -3,17 +3,21 @@ + + #include "unicode/utypes.h" + + #if !UCONFIG_NO_FORMATTING + + #include "charstr.h" + #include "cmemory.h" + #include "cstring.h" ++#ifdef JS_HAS_INTL_API ++#include "double-conversion/string-to-double.h" ++#else + #include "double-conversion-string-to-double.h" ++#endif + #include "measunit_impl.h" + #include "putilimp.h" + #include "uassert.h" + #include "unicode/errorcode.h" + #include "unicode/localpointer.h" + #include "unicode/stringpiece.h" + #include "units_converter.h" + #include +@@ -105,17 +109,21 @@ void Factor::substituteConstants() { + this->constantExponents[i] = 0; + } + } + + namespace { + + /* Helpers */ + ++#ifdef JS_HAS_INTL_API ++using double_conversion::StringToDoubleConverter; ++#else + using icu::double_conversion::StringToDoubleConverter; ++#endif + + // TODO: Make this a shared-utility function. + // Returns `double` from a scientific number(i.e. "1", "2.01" or "3.09E+4") + double strToDouble(StringPiece strNum, UErrorCode &status) { + // We are processing well-formed input, so we don't need any special options to + // StringToDoubleConverter. + StringToDoubleConverter converter(0, 0, 0, "", ""); + int32_t count; diff --git a/gnu/packages/patches/icu4c-bug-1706949-wasi-workaround.patch b/gnu/packages/patches/icu4c-bug-1706949-wasi-workaround.patch new file mode 100644 index 00000000000..2b1a0d32f72 --- /dev/null +++ b/gnu/packages/patches/icu4c-bug-1706949-wasi-workaround.patch @@ -0,0 +1,832 @@ +# Handle WASI lack of support for and . +# +# WASI issue: https://github.com/WebAssembly/wasi-sdk/issues/180 + +diff --git a/source/common/putilimp.h b/source/common/putilimp.h +--- a/source/common/putilimp.h ++++ b/source/common/putilimp.h +@@ -105,10 +105,12 @@ typedef size_t uintptr_t; + #endif + #elif U_PLATFORM == U_PF_OS400 + /* not defined */ + #elif U_PLATFORM == U_PF_HAIKU + /* not defined */ ++#elif defined(__wasi__) ++ /* not defined */ + #else + # define U_TZSET tzset + #endif + + #if defined(U_TIMEZONE) || defined(U_HAVE_TIMEZONE) +@@ -130,10 +132,12 @@ typedef size_t uintptr_t; + /* not defined */ + #elif U_PLATFORM == U_PF_OS400 + /* not defined */ + #elif U_PLATFORM == U_PF_IPHONE + /* not defined */ ++#elif defined(__wasi__) ++ /* not defined */ + #else + # define U_TIMEZONE timezone + #endif + + #if defined(U_TZNAME) || defined(U_HAVE_TZNAME) +@@ -145,10 +149,12 @@ typedef size_t uintptr_t; + #endif + #elif U_PLATFORM == U_PF_OS400 + /* not defined */ + #elif U_PLATFORM == U_PF_HAIKU + /* not defined, (well it is but a loop back to icu) */ ++#elif defined(__wasi__) ++ /* not defined */ + #else + # define U_TZNAME tzname + #endif + + #ifdef U_HAVE_MMAP +diff --git a/source/common/umapfile.h b/source/common/umapfile.h +--- a/source/common/umapfile.h ++++ b/source/common/umapfile.h +@@ -38,10 +38,12 @@ U_CFUNC void uprv_unmapFile(UDataMemory + #define MAP_POSIX 2 + #define MAP_STDIO 3 + + #if UCONFIG_NO_FILE_IO + # define MAP_IMPLEMENTATION MAP_NONE ++#elif defined(__wasi__) ++# define MAP_IMPLEMENTATION MAP_STDIO + #elif U_PLATFORM_USES_ONLY_WIN32_API + # define MAP_IMPLEMENTATION MAP_WIN32 + #elif U_HAVE_MMAP || U_PLATFORM == U_PF_OS390 + # define MAP_IMPLEMENTATION MAP_POSIX + #else /* unknown platform, no memory map implementation: use stdio.h and uprv_malloc() instead */ +diff --git a/source/common/umutex.cpp b/source/common/umutex.cpp +--- a/source/common/umutex.cpp ++++ b/source/common/umutex.cpp +@@ -41,10 +41,11 @@ U_NAMESPACE_BEGIN + * + * ICU Mutex wrappers. + * + *************************************************************************************************/ + ++#ifndef __wasi__ + namespace { + std::mutex *initMutex; + std::condition_variable *initCondition; + + // The ICU global mutex. +@@ -53,32 +54,38 @@ UMutex globalMutex; + + std::once_flag initFlag; + std::once_flag *pInitFlag = &initFlag; + + } // Anonymous namespace ++#endif + + U_CDECL_BEGIN + static UBool U_CALLCONV umtx_cleanup() { ++#ifndef __wasi__ + initMutex->~mutex(); + initCondition->~condition_variable(); + UMutex::cleanup(); + + // Reset the once_flag, by destructing it and creating a fresh one in its place. + // Do not use this trick anywhere else in ICU; use umtx_initOnce, not std::call_once(). + pInitFlag->~once_flag(); + pInitFlag = new(&initFlag) std::once_flag(); ++#endif + return true; + } + + static void U_CALLCONV umtx_init() { ++#ifndef __wasi__ + initMutex = STATIC_NEW(std::mutex); + initCondition = STATIC_NEW(std::condition_variable); + ucln_common_registerCleanup(UCLN_COMMON_MUTEX, umtx_cleanup); ++#endif + } + U_CDECL_END + + ++#ifndef __wasi__ + std::mutex *UMutex::getMutex() { + std::mutex *retPtr = fMutex.load(std::memory_order_acquire); + if (retPtr == nullptr) { + std::call_once(*pInitFlag, umtx_init); + std::lock_guard guard(*initMutex); +@@ -91,41 +98,48 @@ std::mutex *UMutex::getMutex() { + } + } + U_ASSERT(retPtr != nullptr); + return retPtr; + } ++#endif + + UMutex *UMutex::gListHead = nullptr; + + void UMutex::cleanup() { + UMutex *next = nullptr; + for (UMutex *m = gListHead; m != nullptr; m = next) { ++#ifndef __wasi__ + (*m->fMutex).~mutex(); + m->fMutex = nullptr; ++#endif + next = m->fListLink; + m->fListLink = nullptr; + } + gListHead = nullptr; + } + + + U_CAPI void U_EXPORT2 + umtx_lock(UMutex *mutex) { ++#ifndef __wasi__ + if (mutex == nullptr) { + mutex = &globalMutex; + } + mutex->lock(); ++#endif + } + + + U_CAPI void U_EXPORT2 + umtx_unlock(UMutex* mutex) + { ++#ifndef __wasi__ + if (mutex == nullptr) { + mutex = &globalMutex; + } + mutex->unlock(); ++#endif + } + + + /************************************************************************************************* + * +@@ -141,22 +155,26 @@ umtx_unlock(UMutex* mutex) + // that knows the C++ types involved. This function returns true if + // the caller needs to call the Init function. + // + U_COMMON_API UBool U_EXPORT2 + umtx_initImplPreInit(UInitOnce &uio) { ++#ifndef __wasi__ + std::call_once(*pInitFlag, umtx_init); + std::unique_lock lock(*initMutex); ++#endif + if (umtx_loadAcquire(uio.fState) == 0) { + umtx_storeRelease(uio.fState, 1); + return true; // Caller will next call the init function. + } else { ++#ifndef __wasi__ + while (umtx_loadAcquire(uio.fState) == 1) { + // Another thread is currently running the initialization. + // Wait until it completes. + initCondition->wait(lock); + } + U_ASSERT(uio.fState == 2); ++#endif + return false; + } + } + + +@@ -166,15 +184,17 @@ umtx_initImplPreInit(UInitOnce &uio) { + // Some threads may be racing to test the fState variable outside of the mutex, + // requiring the use of store/release when changing its value. + + U_COMMON_API void U_EXPORT2 + umtx_initImplPostInit(UInitOnce &uio) { ++#ifndef __wasi__ + { + std::unique_lock lock(*initMutex); + umtx_storeRelease(uio.fState, 2); + } + initCondition->notify_all(); ++#endif + } + + U_NAMESPACE_END + + /************************************************************************************************* +diff --git a/source/common/umutex.h b/source/common/umutex.h +--- a/source/common/umutex.h ++++ b/source/common/umutex.h +@@ -18,13 +18,16 @@ + */ + + #ifndef UMUTEX_H + #define UMUTEX_H + ++#ifndef __wasi__ + #include + #include + #include ++#endif ++ + #include + + #include "unicode/utypes.h" + #include "unicode/uclean.h" + #include "unicode/uobject.h" +@@ -43,10 +46,12 @@ U_NAMESPACE_BEGIN + * + * Low Level Atomic Operations, ICU wrappers for. + * + ****************************************************************************/ + ++#ifndef __wasi__ ++ + typedef std::atomic u_atomic_int32_t; + + inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { + return var.load(std::memory_order_acquire); + } +@@ -61,10 +66,31 @@ inline int32_t umtx_atomic_inc(u_atomic_ + + inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) { + return var->fetch_sub(1) - 1; + } + ++#else ++ ++typedef int32_t u_atomic_int32_t; ++ ++inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { ++ return var; ++} ++ ++inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) { ++ var = val; ++} ++ ++inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) { ++ return ++(*var); ++} ++ ++inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) { ++ return --(*var); ++} ++ ++#endif + + /************************************************************************************************* + * + * UInitOnce Definitions. + * +@@ -211,21 +237,29 @@ public: + U_COMMON_API UMutex& operator=(const UMutex& other) = delete; + U_COMMON_API void* operator new(size_t) = delete; + + // requirements for C++ BasicLockable, allows UMutex to work with std::lock_guard + U_COMMON_API void lock() { ++#ifndef __wasi__ + std::mutex *m = fMutex.load(std::memory_order_acquire); + if (m == nullptr) { m = getMutex(); } + m->lock(); ++#endif + } +- U_COMMON_API void unlock() { fMutex.load(std::memory_order_relaxed)->unlock(); } ++ U_COMMON_API void unlock() { ++#ifndef __wasi__ ++ fMutex.load(std::memory_order_relaxed)->unlock(); ++#endif ++ } + + U_COMMON_API static void cleanup(); + + private: ++#ifndef __wasi__ + alignas(std::mutex) char fStorage[sizeof(std::mutex)] {}; + std::atomic fMutex { nullptr }; ++#endif + + /** All initialized UMutexes are kept in a linked list, so that they can be found, + * and the underlying std::mutex destructed, by u_cleanup(). + */ + UMutex *fListLink { nullptr }; +@@ -233,11 +267,13 @@ private: + + /** Out-of-line function to lazily initialize a UMutex on first use. + * Initial fast check is inline, in lock(). The returned value may never + * be nullptr. + */ ++#ifndef __wasi__ + std::mutex *getMutex(); ++#endif + }; + + + /* Lock a mutex. + * @param mutex The given mutex to be locked. Pass NULL to specify +diff --git a/source/common/unifiedcache.cpp b/source/common/unifiedcache.cpp +--- a/source/common/unifiedcache.cpp ++++ b/source/common/unifiedcache.cpp +@@ -11,19 +11,23 @@ + */ + + #include "unifiedcache.h" + + #include // For std::max() ++#ifndef __wasi__ + #include ++#endif + + #include "uassert.h" + #include "uhash.h" + #include "ucln_cmn.h" + + static icu::UnifiedCache *gCache = nullptr; ++#ifndef __wasi__ + static std::mutex *gCacheMutex = nullptr; + static std::condition_variable *gInProgressValueAddedCond; ++#endif + static icu::UInitOnce gCacheInitOnce {}; + + static const int32_t MAX_EVICT_ITERATIONS = 10; + static const int32_t DEFAULT_MAX_UNUSED = 1000; + static const int32_t DEFAULT_PERCENTAGE_OF_IN_USE = 100; +@@ -32,14 +36,16 @@ static const int32_t DEFAULT_PERCENTAGE_ + U_CDECL_BEGIN + static UBool U_CALLCONV unifiedcache_cleanup() { + gCacheInitOnce.reset(); + delete gCache; + gCache = nullptr; ++#ifndef __wasi__ + gCacheMutex->~mutex(); + gCacheMutex = nullptr; + gInProgressValueAddedCond->~condition_variable(); + gInProgressValueAddedCond = nullptr; ++#endif + return true; + } + U_CDECL_END + + +@@ -70,12 +76,14 @@ CacheKeyBase::~CacheKeyBase() { + static void U_CALLCONV cacheInit(UErrorCode &status) { + U_ASSERT(gCache == nullptr); + ucln_common_registerCleanup( + UCLN_COMMON_UNIFIED_CACHE, unifiedcache_cleanup); + ++#ifndef __wasi__ + gCacheMutex = STATIC_NEW(std::mutex); + gInProgressValueAddedCond = STATIC_NEW(std::condition_variable); ++#endif + gCache = new UnifiedCache(status); + if (gCache == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + } + if (U_FAILURE(status)) { +@@ -133,41 +141,53 @@ void UnifiedCache::setEvictionPolicy( + } + if (count < 0 || percentageOfInUseItems < 0) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return; + } ++#ifndef __wasi__ + std::lock_guard lock(*gCacheMutex); ++#endif + fMaxUnused = count; + fMaxPercentageOfInUse = percentageOfInUseItems; + } + + int32_t UnifiedCache::unusedCount() const { ++#ifndef __wasi__ + std::lock_guard lock(*gCacheMutex); ++#endif + return uhash_count(fHashtable) - fNumValuesInUse; + } + + int64_t UnifiedCache::autoEvictedCount() const { ++#ifndef __wasi__ + std::lock_guard lock(*gCacheMutex); ++#endif + return fAutoEvictedCount; + } + + int32_t UnifiedCache::keyCount() const { ++#ifndef __wasi__ + std::lock_guard lock(*gCacheMutex); ++#endif + return uhash_count(fHashtable); + } + + void UnifiedCache::flush() const { ++#ifndef __wasi__ + std::lock_guard lock(*gCacheMutex); ++#endif + + // Use a loop in case cache items that are flushed held hard references to + // other cache items making those additional cache items eligible for + // flushing. + while (_flush(false)); + } + + void UnifiedCache::handleUnreferencedObject() const { ++#ifndef __wasi__ + std::lock_guard lock(*gCacheMutex); ++#endif + --fNumValuesInUse; + _runEvictionSlice(); + } + + #ifdef UNIFIED_CACHE_DEBUG +@@ -182,11 +202,13 @@ void UnifiedCache::dump() { + } + cache->dumpContents(); + } + + void UnifiedCache::dumpContents() const { ++#ifndef __wasi__ + std::lock_guard lock(*gCacheMutex); ++#endif + _dumpContents(); + } + + // Dumps content of cache. + // On entry, gCacheMutex must be held. +@@ -222,11 +244,13 @@ UnifiedCache::~UnifiedCache() { + flush(); + { + // Now all that should be left in the cache are entries that refer to + // each other and entries with hard references from outside the cache. + // Nothing we can do about these so proceed to wipe out the cache. ++#ifndef __wasi__ + std::lock_guard lock(*gCacheMutex); ++#endif + _flush(true); + } + uhash_close(fHashtable); + fHashtable = nullptr; + delete fNoValue; +@@ -323,11 +347,13 @@ void UnifiedCache::_putNew( + + void UnifiedCache::_putIfAbsentAndGet( + const CacheKeyBase &key, + const SharedObject *&value, + UErrorCode &status) const { ++#ifndef __wasi__ + std::lock_guard lock(*gCacheMutex); ++#endif + const UHashElement *element = uhash_find(fHashtable, &key); + if (element != nullptr && !_inProgress(element)) { + _fetch(element, value, status); + return; + } +@@ -348,18 +374,22 @@ UBool UnifiedCache::_poll( + const CacheKeyBase &key, + const SharedObject *&value, + UErrorCode &status) const { + U_ASSERT(value == nullptr); + U_ASSERT(status == U_ZERO_ERROR); ++#ifndef __wasi__ + std::unique_lock lock(*gCacheMutex); ++#endif + const UHashElement *element = uhash_find(fHashtable, &key); + + // If the hash table contains an inProgress placeholder entry for this key, + // this means that another thread is currently constructing the value object. + // Loop, waiting for that construction to complete. + while (element != nullptr && _inProgress(element)) { ++#ifndef __wasi__ + gInProgressValueAddedCond->wait(lock); ++#endif + element = uhash_find(fHashtable, &key); + } + + // If the hash table contains an entry for the key, + // fetch out the contents and return them. +@@ -426,13 +456,15 @@ void UnifiedCache::_put( + UHashElement *ptr = const_cast(element); + ptr->value.pointer = (void *) value; + U_ASSERT(oldValue == fNoValue); + removeSoftRef(oldValue); + ++#ifndef __wasi__ + // Tell waiting threads that we replace in-progress status with + // an error. + gInProgressValueAddedCond->notify_all(); ++#endif + } + + void UnifiedCache::_fetch( + const UHashElement *element, + const SharedObject *&value, +diff --git a/source/i18n/decContext.h b/source/i18n/decContext.h +--- a/source/i18n/decContext.h ++++ b/source/i18n/decContext.h +@@ -59,11 +59,13 @@ + + #if !defined(int32_t) + /* #include */ /* C99 standard integers */ + #endif + #include /* for printf, etc. */ ++#ifndef __wasi__ + #include /* for traps */ ++#endif + + /* Extended flags setting -- set this to 0 to use only IEEE flags */ + #if !defined(DECEXTFLAG) + #define DECEXTFLAG 1 /* 1=enable extended flags */ + #endif +diff --git a/source/i18n/decimfmt.cpp b/source/i18n/decimfmt.cpp +--- a/source/i18n/decimfmt.cpp ++++ b/source/i18n/decimfmt.cpp +@@ -478,12 +478,17 @@ DecimalFormat& DecimalFormat::operator=( + } + + DecimalFormat::~DecimalFormat() { + if (fields == nullptr) { return; } + ++#ifndef __wasi__ + delete fields->atomicParser.exchange(nullptr); + delete fields->atomicCurrencyParser.exchange(nullptr); ++#else ++ delete fields->atomicParser; ++ delete fields->atomicCurrencyParser; ++#endif + delete fields; + } + + DecimalFormat* DecimalFormat::clone() const { + // can only clone valid objects. +@@ -1635,12 +1640,17 @@ void DecimalFormat::touch(UErrorCode& st + + // Do this after fields->exportedProperties are set up + setupFastFormat(); + + // Delete the parsers if they were made previously ++#ifndef __wasi__ + delete fields->atomicParser.exchange(nullptr); + delete fields->atomicCurrencyParser.exchange(nullptr); ++#else ++ delete fields->atomicParser; ++ delete fields->atomicCurrencyParser; ++#endif + + // In order for the getters to work, we need to populate some fields in NumberFormat. + NumberFormat::setCurrency(fields->exportedProperties.currency.get(status).getISOCurrency(), status); + NumberFormat::setMaximumIntegerDigits(fields->exportedProperties.maximumIntegerDigits); + NumberFormat::setMinimumIntegerDigits(fields->exportedProperties.minimumIntegerDigits); +@@ -1671,11 +1681,15 @@ const numparse::impl::NumberParserImpl* + if (U_FAILURE(status)) { + return nullptr; + } + + // First try to get the pre-computed parser ++#ifndef __wasi__ + auto* ptr = fields->atomicParser.load(); ++#else ++ auto* ptr = fields->atomicParser; ++#endif + if (ptr != nullptr) { + return ptr; + } + + // Try computing the parser on our own +@@ -1690,25 +1704,34 @@ const numparse::impl::NumberParserImpl* + + // Note: ptr starts as nullptr; during compare_exchange, + // it is set to what is actually stored in the atomic + // if another thread beat us to computing the parser object. + auto* nonConstThis = const_cast(this); ++#ifndef __wasi__ + if (!nonConstThis->fields->atomicParser.compare_exchange_strong(ptr, temp)) { + // Another thread beat us to computing the parser + delete temp; + return ptr; + } else { + // Our copy of the parser got stored in the atomic + return temp; + } ++#else ++ nonConstThis->fields->atomicParser = temp; ++ return temp; ++#endif + } + + const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorCode& status) const { + if (U_FAILURE(status)) { return nullptr; } + + // First try to get the pre-computed parser ++#ifndef __wasi__ + auto* ptr = fields->atomicCurrencyParser.load(); ++#else ++ auto* ptr = fields->atomicCurrencyParser; ++#endif + if (ptr != nullptr) { + return ptr; + } + + // Try computing the parser on our own +@@ -1719,18 +1742,23 @@ const numparse::impl::NumberParserImpl* + } + + // Note: ptr starts as nullptr; during compare_exchange, it is set to what is actually stored in the + // atomic if another thread beat us to computing the parser object. + auto* nonConstThis = const_cast(this); ++#ifndef __wasi__ + if (!nonConstThis->fields->atomicCurrencyParser.compare_exchange_strong(ptr, temp)) { + // Another thread beat us to computing the parser + delete temp; + return ptr; + } else { + // Our copy of the parser got stored in the atomic + return temp; + } ++#else ++ nonConstThis->fields->atomicCurrencyParser = temp; ++ return temp; ++#endif + } + + void + DecimalFormat::fieldPositionHelper( + const UFormattedNumberData& formatted, +diff --git a/source/i18n/number_mapper.h b/source/i18n/number_mapper.h +--- a/source/i18n/number_mapper.h ++++ b/source/i18n/number_mapper.h +@@ -5,18 +5,21 @@ + + #if !UCONFIG_NO_FORMATTING + #ifndef __NUMBER_MAPPER_H__ + #define __NUMBER_MAPPER_H__ + +-#include + #include "number_types.h" + #include "unicode/currpinf.h" + #include "standardplural.h" + #include "number_patternstring.h" + #include "number_currencysymbols.h" + #include "numparse_impl.h" + ++#ifndef __wasi__ ++#include ++#endif ++ + U_NAMESPACE_BEGIN + namespace number::impl { + + class AutoAffixPatternProvider; + class CurrencyPluralInfoAffixProvider; +@@ -194,14 +197,22 @@ struct DecimalFormatFields : public UMem + * #format} method uses the formatter directly without needing to synchronize. + */ + LocalizedNumberFormatter formatter; + + /** The lazy-computed parser for .parse() */ ++#ifndef __wasi__ + std::atomic<::icu::numparse::impl::NumberParserImpl*> atomicParser = {}; ++#else ++ ::icu::numparse::impl::NumberParserImpl* atomicParser = nullptr; ++#endif + + /** The lazy-computed parser for .parseCurrency() */ ++#ifndef __wasi__ + std::atomic<::icu::numparse::impl::NumberParserImpl*> atomicCurrencyParser = {}; ++#else ++ ::icu::numparse::impl::NumberParserImpl* atomicCurrencyParser = {}; ++#endif + + /** Small object ownership warehouse for the formatter and parser */ + DecimalFormatWarehouse warehouse; + + /** The effective properties as exported from the formatter object. Used by some getters. */ +diff --git a/source/i18n/numrange_fluent.cpp b/source/i18n/numrange_fluent.cpp +--- a/source/i18n/numrange_fluent.cpp ++++ b/source/i18n/numrange_fluent.cpp +@@ -246,33 +246,53 @@ LocalizedNumberRangeFormatter::Localized + + LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(NFS&& src) noexcept + : NFS(std::move(src)) { + // Steal the compiled formatter + LNF&& _src = static_cast(src); ++#ifndef __wasi__ + auto* stolen = _src.fAtomicFormatter.exchange(nullptr); + delete fAtomicFormatter.exchange(stolen); ++#else ++ delete fAtomicFormatter; ++ fAtomicFormatter = _src.fAtomicFormatter; ++ _src.fAtomicFormatter = nullptr; ++#endif + } + + LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(const LNF& other) { + if (this == &other) { return *this; } // self-assignment: no-op + NFS::operator=(static_cast&>(other)); + // Do not steal; just clear ++#ifndef __wasi__ + delete fAtomicFormatter.exchange(nullptr); ++#else ++ delete fAtomicFormatter; ++#endif + return *this; + } + + LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(LNF&& src) noexcept { + NFS::operator=(static_cast&&>(src)); + // Steal the compiled formatter ++#ifndef __wasi__ + auto* stolen = src.fAtomicFormatter.exchange(nullptr); + delete fAtomicFormatter.exchange(stolen); ++#else ++ delete fAtomicFormatter; ++ fAtomicFormatter = src.fAtomicFormatter; ++ src.fAtomicFormatter = nullptr; ++#endif + return *this; + } + + + LocalizedNumberRangeFormatter::~LocalizedNumberRangeFormatter() { ++#ifndef __wasi__ + delete fAtomicFormatter.exchange(nullptr); ++#else ++ delete fAtomicFormatter; ++#endif + } + + LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const RangeMacroProps& macros, const Locale& locale) { + fMacros = macros; + fMacros.locale = locale; +@@ -363,11 +383,15 @@ LocalizedNumberRangeFormatter::getFormat + if (U_FAILURE(status)) { + return nullptr; + } + + // First try to get the pre-computed formatter ++#ifndef __wasi__ + auto* ptr = fAtomicFormatter.load(); ++#else ++ auto* ptr = fAtomicFormatter; ++#endif + if (ptr != nullptr) { + return ptr; + } + + // Try computing the formatter on our own +@@ -378,17 +402,22 @@ LocalizedNumberRangeFormatter::getFormat + + // Note: ptr starts as nullptr; during compare_exchange, + // it is set to what is actually stored in the atomic + // if another thread beat us to computing the formatter object. + auto* nonConstThis = const_cast(this); ++#ifndef __wasi__ + if (!nonConstThis->fAtomicFormatter.compare_exchange_strong(ptr, temp.getAlias())) { + // Another thread beat us to computing the formatter + return ptr; + } else { + // Our copy of the formatter got stored in the atomic + return temp.orphan(); + } ++#else ++ nonConstThis->fAtomicFormatter = temp.getAlias(); ++ return temp.orphan(); ++#endif + + } + + + #endif /* #if !UCONFIG_NO_FORMATTING */ +diff --git a/source/i18n/unicode/numberrangeformatter.h b/source/i18n/unicode/numberrangeformatter.h +--- a/source/i18n/unicode/numberrangeformatter.h ++++ b/source/i18n/unicode/numberrangeformatter.h +@@ -8,18 +8,21 @@ + + #if U_SHOW_CPLUSPLUS_API + + #if !UCONFIG_NO_FORMATTING + +-#include + #include "unicode/appendable.h" + #include "unicode/fieldpos.h" + #include "unicode/formattedvalue.h" + #include "unicode/fpositer.h" + #include "unicode/numberformatter.h" + #include "unicode/unumberrangeformatter.h" + ++#ifndef __wasi__ ++#include ++#endif ++ + /** + * \file + * \brief C++ API: Library for localized formatting of number, currency, and unit ranges. + * + * The main entrypoint to the formatting of ranges of numbers, including currencies and other units of measurement. +@@ -559,11 +562,15 @@ class U_I18N_API_CLASS LocalizedNumberRa + * @stable ICU 63 + */ + U_I18N_API ~LocalizedNumberRangeFormatter(); + + private: ++#ifndef __wasi__ + std::atomic fAtomicFormatter = {}; ++#else ++ impl::NumberRangeFormatterImpl* fAtomicFormatter = nullptr; ++#endif + + const impl::NumberRangeFormatterImpl* getFormatter(UErrorCode& stauts) const; + + explicit LocalizedNumberRangeFormatter( + const NumberRangeFormatterSettings& other); diff --git a/gnu/packages/patches/icu4c-bug-1790071-ICU-22132-standardize-vtzone-output.patch b/gnu/packages/patches/icu4c-bug-1790071-ICU-22132-standardize-vtzone-output.patch new file mode 100644 index 00000000000..6f9bfacbe92 --- /dev/null +++ b/gnu/packages/patches/icu4c-bug-1790071-ICU-22132-standardize-vtzone-output.patch @@ -0,0 +1,28 @@ +diff --git a/source/i18n/vtzone.cpp b/source/i18n/vtzone.cpp +--- a/source/i18n/vtzone.cpp ++++ b/source/i18n/vtzone.cpp +@@ -1735,14 +1735,17 @@ VTimeZone::write(VTZWriter& writer, UErr + } + } + } else { +- UnicodeString icutzprop; +- UVector customProps(nullptr, uhash_compareUnicodeString, status); ++ UVector customProps(uprv_deleteUObject, uhash_compareUnicodeString, status); + if (olsonzid.length() > 0 && icutzver.length() > 0) { +- icutzprop.append(olsonzid); +- icutzprop.append(u'['); +- icutzprop.append(icutzver); +- icutzprop.append(u']'); +- customProps.addElement(&icutzprop, status); ++ LocalPointer icutzprop(new UnicodeString(ICU_TZINFO_PROP), status); ++ if (U_FAILURE(status)) { ++ return; ++ } ++ icutzprop->append(olsonzid); ++ icutzprop->append(u'['); ++ icutzprop->append(icutzver); ++ icutzprop->append(u']'); ++ customProps.adoptElement(icutzprop.orphan(), status); + } + writeZone(writer, *tz, &customProps, status); + } diff --git a/gnu/packages/patches/icu4c-bug-1856290-ICU-20548-dateinterval-timezone.patch b/gnu/packages/patches/icu4c-bug-1856290-ICU-20548-dateinterval-timezone.patch new file mode 100644 index 00000000000..b6d518c76be --- /dev/null +++ b/gnu/packages/patches/icu4c-bug-1856290-ICU-20548-dateinterval-timezone.patch @@ -0,0 +1,163 @@ +# Handle 'O' time zone skeleton in DateIntervalFormat. +# Keep time zone skeleton field widths in DateIntervalFormat. +# +# ICU bug: https://unicode-org.atlassian.net/browse/ICU-20548 + +diff --git a/source/i18n/dtitv_impl.h b/source/i18n/dtitv_impl.h +--- a/source/i18n/dtitv_impl.h ++++ b/source/i18n/dtitv_impl.h +@@ -84,16 +84,19 @@ + #define CAP_W ((char16_t)0x0057) + #define CAP_Y ((char16_t)0x0059) + #define CAP_Z ((char16_t)0x005A) + + //#define MINIMUM_SUPPORTED_CALENDAR_FIELD UCAL_MINUTE + + #define MAX_E_COUNT 5 + #define MAX_M_COUNT 5 ++#define MAX_z_COUNT 4 ++#define MAX_v_COUNT 4 ++#define MAX_O_COUNT 4 + //#define MAX_INTERVAL_INDEX 4 + #define MAX_POSITIVE_INT 56632 + + + #endif /* #if !UCONFIG_NO_FORMATTING */ + + #endif + //eof +diff --git a/source/i18n/dtitvfmt.cpp b/source/i18n/dtitvfmt.cpp +--- a/source/i18n/dtitvfmt.cpp ++++ b/source/i18n/dtitvfmt.cpp +@@ -1061,16 +1061,17 @@ DateIntervalFormat::getDateTimeSkeleton( + // 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 mCount = 0; + int32_t vCount = 0; + int32_t zCount = 0; ++ int32_t OCount = 0; + char16_t hourChar = u'\0'; + int32_t i; + + for (i = 0; i < skeleton.length(); ++i) { + char16_t ch = skeleton[i]; + switch ( ch ) { + case CAP_E: + dateSkeleton.append(ch); +@@ -1123,16 +1124,20 @@ DateIntervalFormat::getDateTimeSkeleton( + case LOW_Z: + ++zCount; + timeSkeleton.append(ch); + break; + case LOW_V: + ++vCount; + timeSkeleton.append(ch); + break; ++ case CAP_O: ++ ++OCount; ++ timeSkeleton.append(ch); ++ break; + case LOW_A: + case CAP_V: + case CAP_Z: + case LOW_J: + case LOW_S: + case CAP_S: + case CAP_A: + case LOW_B: +@@ -1174,20 +1179,41 @@ DateIntervalFormat::getDateTimeSkeleton( + /* generate normalized form for time */ + if ( hourChar != u'\0' ) { + normalizedTimeSkeleton.append(hourChar); + } + if ( mCount != 0 ) { + normalizedTimeSkeleton.append(LOW_M); + } + if ( zCount != 0 ) { +- normalizedTimeSkeleton.append(LOW_Z); ++ if ( zCount <= 3 ) { ++ normalizedTimeSkeleton.append(LOW_Z); ++ } else { ++ for ( int32_t j = 0; j < zCount && j < MAX_z_COUNT; ++j ) { ++ normalizedTimeSkeleton.append(LOW_Z); ++ } ++ } + } + if ( vCount != 0 ) { +- normalizedTimeSkeleton.append(LOW_V); ++ if ( vCount <= 3 ) { ++ normalizedTimeSkeleton.append(LOW_V); ++ } else { ++ for ( int32_t j = 0; j < vCount && j < MAX_v_COUNT; ++j ) { ++ normalizedTimeSkeleton.append(LOW_V); ++ } ++ } ++ } ++ if ( OCount != 0 ) { ++ if ( OCount <= 3 ) { ++ normalizedTimeSkeleton.append(CAP_O); ++ } else { ++ for ( int32_t j = 0; j < OCount && j < MAX_O_COUNT; ++j ) { ++ normalizedTimeSkeleton.append(CAP_O); ++ } ++ } + } + } + + + /** + * Generate date or time interval pattern from resource, + * and set them into the interval pattern locale to this formatter. + * +@@ -1732,18 +1758,23 @@ DateIntervalFormat::adjustFieldWidth(con + findReplaceInPattern(adjustedPtn, UnicodeString(u"a\u202F",-1), UnicodeString()); + findReplaceInPattern(adjustedPtn, UnicodeString(LOW_A), UnicodeString()); + // adjust interior double spaces, remove exterior whitespace + findReplaceInPattern(adjustedPtn, UnicodeString(" "), UnicodeString(" ")); + adjustedPtn.trim(); + } + if ( differenceInfo == 2 ) { + if (inputSkeleton.indexOf(LOW_Z) != -1) { ++ bestMatchSkeletonFieldWidth[(int)(LOW_Z - PATTERN_CHAR_BASE)] = bestMatchSkeletonFieldWidth[(int)(LOW_V - PATTERN_CHAR_BASE)]; + findReplaceInPattern(adjustedPtn, UnicodeString(LOW_V), UnicodeString(LOW_Z)); + } ++ if (inputSkeleton.indexOf(CAP_O) != -1) { ++ bestMatchSkeletonFieldWidth[(int)(CAP_O - PATTERN_CHAR_BASE)] = bestMatchSkeletonFieldWidth[(int)(LOW_V - PATTERN_CHAR_BASE)]; ++ findReplaceInPattern(adjustedPtn, UnicodeString(LOW_V), UnicodeString(CAP_O)); ++ } + if (inputSkeleton.indexOf(CAP_K) != -1) { + findReplaceInPattern(adjustedPtn, UnicodeString(LOW_H), UnicodeString(CAP_K)); + } + if (inputSkeleton.indexOf(LOW_K) != -1) { + findReplaceInPattern(adjustedPtn, UnicodeString(CAP_H), UnicodeString(LOW_K)); + } + if (inputSkeleton.indexOf(LOW_B) != -1) { + findReplaceInPattern(adjustedPtn, UnicodeString(LOW_A), UnicodeString(LOW_B)); +diff --git a/source/i18n/dtitvinf.cpp b/source/i18n/dtitvinf.cpp +--- a/source/i18n/dtitvinf.cpp ++++ b/source/i18n/dtitvinf.cpp +@@ -582,19 +582,20 @@ DateIntervalInfo::getBestSkeleton(const + + // hack for certain alternate characters + // resource bundles only have time skeletons containing 'v', 'h', and 'H' + // but not time skeletons containing 'z', 'K', or 'k' + // the skeleton may also include 'a' or 'b', which never occur in the resource bundles, so strip them out too + UBool replacedAlternateChars = false; + const UnicodeString* inputSkeleton = &skeleton; + UnicodeString copySkeleton; +- if ( skeleton.indexOf(LOW_Z) != -1 || skeleton.indexOf(LOW_K) != -1 || skeleton.indexOf(CAP_K) != -1 || skeleton.indexOf(LOW_A) != -1 || skeleton.indexOf(LOW_B) != -1 ) { ++ if ( skeleton.indexOf(LOW_Z) != -1 || skeleton.indexOf(CAP_O) != -1 || skeleton.indexOf(LOW_K) != -1 || skeleton.indexOf(CAP_K) != -1 || skeleton.indexOf(LOW_A) != -1 || skeleton.indexOf(LOW_B) != -1 ) { + copySkeleton = skeleton; + copySkeleton.findAndReplace(UnicodeString(LOW_Z), UnicodeString(LOW_V)); ++ copySkeleton.findAndReplace(UnicodeString(CAP_O), UnicodeString(LOW_V)); + copySkeleton.findAndReplace(UnicodeString(LOW_K), UnicodeString(CAP_H)); + copySkeleton.findAndReplace(UnicodeString(CAP_K), UnicodeString(LOW_H)); + copySkeleton.findAndReplace(UnicodeString(LOW_A), UnicodeString()); + copySkeleton.findAndReplace(UnicodeString(LOW_B), UnicodeString()); + inputSkeleton = ©Skeleton; + replacedAlternateChars = true; + } + diff --git a/gnu/packages/patches/icu4c-bug-1954138-dtitvfmt-adopt-calendar.patch b/gnu/packages/patches/icu4c-bug-1954138-dtitvfmt-adopt-calendar.patch new file mode 100644 index 00000000000..5a0f573203d --- /dev/null +++ b/gnu/packages/patches/icu4c-bug-1954138-dtitvfmt-adopt-calendar.patch @@ -0,0 +1,69 @@ +diff --git a/source/i18n/dtitvfmt.cpp b/source/i18n/dtitvfmt.cpp +--- a/source/i18n/dtitvfmt.cpp ++++ b/source/i18n/dtitvfmt.cpp +@@ -630,16 +630,38 @@ DateIntervalFormat::getTimeZone() const + { + if (fDateFormat != nullptr) { + Mutex lock(&gFormatterMutex); + return fDateFormat->getTimeZone(); + } + // If fDateFormat is nullptr (unexpected), create default timezone. + return *(TimeZone::createDefault()); + } ++ ++void DateIntervalFormat::adoptCalendar(Calendar *calendarToAdopt) { ++ if (fDateFormat != nullptr) { ++ fDateFormat->adoptCalendar(calendarToAdopt); ++ } ++ ++ // The fDateFormat has the primary calendar for the DateIntervalFormat and has ++ // ownership of any adopted Calendar; fFromCalendar and fToCalendar are internal ++ // work clones of that calendar. ++ ++ delete fFromCalendar; ++ fFromCalendar = nullptr; ++ ++ delete fToCalendar; ++ fToCalendar = nullptr; ++ ++ const Calendar *calendar = fDateFormat->getCalendar(); ++ if (calendar != nullptr) { ++ fFromCalendar = calendar->clone(); ++ fToCalendar = calendar->clone(); ++ } ++} + + void + DateIntervalFormat::setContext(UDisplayContext value, UErrorCode& status) + { + if (U_FAILURE(status)) + return; + if (static_cast(static_cast(value) >> 8) == UDISPCTX_TYPE_CAPITALIZATION) { + fCapitalizationContext = value; +diff --git a/source/i18n/unicode/dtitvfmt.h b/source/i18n/unicode/dtitvfmt.h +--- a/source/i18n/unicode/dtitvfmt.h ++++ b/source/i18n/unicode/dtitvfmt.h +@@ -625,16 +625,23 @@ public: + /** + * Sets the time zone for the calendar used by this DateIntervalFormat object. + * @param zone the new time zone. + * @stable ICU 4.8 + */ + U_I18N_API virtual void setTimeZone(const TimeZone& zone); + + /** ++ * Sets the calendar used by this DateIntervalFormat object. The caller no longer owns ++ * the Calendar object and should not delete it after this call. ++ * @param calendarToAdopt the Calendar to be adopted. ++ */ ++ U_I18N_API virtual void adoptCalendar(Calendar *calendarToAdopt); ++ ++ /** + * Set a particular UDisplayContext value in the formatter, such as + * UDISPCTX_CAPITALIZATION_FOR_STANDALONE. This causes the formatted + * result to be capitalized appropriately for the context in which + * it is intended to be used, considering both the locale and the + * type of field at the beginning of the formatted result. + * @param value The UDisplayContext value to set. + * @param status Input/output status. If at entry this indicates a failure + * status, the function will do nothing; otherwise this will be diff --git a/gnu/packages/patches/icu4c-bug-1972781-chinese-based-calendar.patch b/gnu/packages/patches/icu4c-bug-1972781-chinese-based-calendar.patch new file mode 100644 index 00000000000..5bcca8b6212 --- /dev/null +++ b/gnu/packages/patches/icu4c-bug-1972781-chinese-based-calendar.patch @@ -0,0 +1,25 @@ +diff --git a/source/i18n/smpdtfmt.cpp b/source/i18n/smpdtfmt.cpp +--- a/source/i18n/smpdtfmt.cpp ++++ b/source/i18n/smpdtfmt.cpp +@@ -1523,18 +1523,19 @@ SimpleDateFormat::subFormat(UnicodeStrin + } + + switch (patternCharIndex) { + + // for any "G" symbol, write out the appropriate era string + // "GGGG" is wide era name, "GGGGG" is narrow era name, anything else is abbreviated name + case UDAT_ERA_FIELD: + { +- if (typeid(cal) == typeid(ChineseCalendar) || +- typeid(cal) == typeid(DangiCalendar)) { ++ const char* type = cal.getType(); ++ if (strcmp(type, "chinese") == 0 || ++ strcmp(type, "dangi") == 0) { + zeroPaddingNumber(currentNumberFormat,appendTo, value, 1, 9); // as in ICU4J + } else { + if (count == 5) { + _appendSymbol(appendTo, value, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount); + capContextUsageType = DateFormatSymbols::kCapContextUsageEraNarrow; + } else if (count == 4) { + _appendSymbol(appendTo, value, fSymbols->fEraNames, fSymbols->fEraNamesCount); + capContextUsageType = DateFormatSymbols::kCapContextUsageEraWide; diff --git a/gnu/packages/patches/icu4c-bug-2000225-ICU-23264-increase-measure-unit-capacity.patch b/gnu/packages/patches/icu4c-bug-2000225-ICU-23264-increase-measure-unit-capacity.patch new file mode 100644 index 00000000000..2f9bae22eac --- /dev/null +++ b/gnu/packages/patches/icu4c-bug-2000225-ICU-23264-increase-measure-unit-capacity.patch @@ -0,0 +1,27 @@ +# Increase measure unit capacity for ICU 78. +# +# ICU bug: https://unicode-org.atlassian.net/browse/ICU-23264 + +diff --git a/source/i18n/number_skeletons.cpp b/source/i18n/number_skeletons.cpp +--- a/source/i18n/number_skeletons.cpp ++++ b/source/i18n/number_skeletons.cpp +@@ -1067,18 +1067,17 @@ void blueprint_helpers::parseMeasureUnit + } + + // Need to do char <-> char16_t conversion... + CharString type; + SKELETON_UCHAR_TO_CHAR(type, stemString, 0, firstHyphen, status); + CharString subType; + SKELETON_UCHAR_TO_CHAR(subType, stemString, firstHyphen + 1, stemString.length(), status); + +- // Note: the largest type as of this writing (Aug 2020) is "volume", which has 33 units. +- static constexpr int32_t CAPACITY = 40; ++ static constexpr int32_t CAPACITY = 50; + MeasureUnit units[CAPACITY]; + UErrorCode localStatus = U_ZERO_ERROR; + int32_t numUnits = MeasureUnit::getAvailable(type.data(), units, CAPACITY, localStatus); + if (U_FAILURE(localStatus)) { + // More than 30 units in this type? + status = U_INTERNAL_PROGRAM_ERROR; + return; + } diff --git a/gnu/packages/patches/icu4c-bug-2002735-ICU-23277-coptic-single-era.patch b/gnu/packages/patches/icu4c-bug-2002735-ICU-23277-coptic-single-era.patch new file mode 100644 index 00000000000..e6cba7e2ee2 --- /dev/null +++ b/gnu/packages/patches/icu4c-bug-2002735-ICU-23277-coptic-single-era.patch @@ -0,0 +1,109 @@ +diff --git a/source/i18n/coptccal.cpp b/source/i18n/coptccal.cpp +--- a/source/i18n/coptccal.cpp ++++ b/source/i18n/coptccal.cpp +@@ -61,46 +61,43 @@ int32_t + CopticCalendar::handleGetExtendedYear(UErrorCode& status) + { + if (U_FAILURE(status)) { + return 0; + } + if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) { + return internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1 + } +- // The year defaults to the epoch start, the era to CE +- int32_t era = internalGet(UCAL_ERA, CE); +- if (era == BCE) { +- return 1 - internalGet(UCAL_YEAR, 1); // Convert to extended year +- } +- if (era == CE){ +- return internalGet(UCAL_YEAR, 1); // Default to year 1 +- } +- status = U_ILLEGAL_ARGUMENT_ERROR; +- return 0; ++ // The year defaults to the epoch start ++ return internalGet(UCAL_YEAR, 1); // Default to year 1 + } + + IMPL_SYSTEM_DEFAULT_CENTURY(CopticCalendar, "@calendar=coptic") + + int32_t + CopticCalendar::getJDEpochOffset() const + { + return COPTIC_JD_EPOCH_OFFSET; + } + + int32_t CopticCalendar::extendedYearToEra(int32_t extendedYear) const { +- return extendedYear <= 0 ? BCE : CE; ++ return CE; + } + + int32_t CopticCalendar::extendedYearToYear(int32_t extendedYear) const { +- return extendedYear <= 0 ? 1 - extendedYear : extendedYear; ++ return extendedYear; + } + +-bool CopticCalendar::isEra0CountingBackward() const { +- return true; ++int32_t ++CopticCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const ++{ ++ if (field == UCAL_ERA) { ++ return 1; // Only one era, era is always 1 ++ } ++ return CECalendar::handleGetLimit(field, limitType); + } + + int32_t + CopticCalendar::getRelatedYearDifference() const { + constexpr int32_t kCopticCalendarRelatedYearDifference = 284; + return kCopticCalendarRelatedYearDifference; + } + +diff --git a/source/i18n/coptccal.h b/source/i18n/coptccal.h +--- a/source/i18n/coptccal.h ++++ b/source/i18n/coptccal.h +@@ -165,16 +165,22 @@ protected: + int32_t getRelatedYearDifference() const override; + + /** + * Return the extended year defined by the current fields. + * @internal + */ + virtual int32_t handleGetExtendedYear(UErrorCode& status) override; + ++ /** ++ * Calculate the limit for a specified type of limit and field ++ * @internal ++ */ ++ virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const override; ++ + DECLARE_OVERRIDE_SYSTEM_DEFAULT_CENTURY + + /** + * Return the date offset from Julian + * @internal + */ + int32_t getJDEpochOffset() const override; + +@@ -184,21 +190,16 @@ protected: + */ + int32_t extendedYearToEra(int32_t extendedYear) const override; + + /** + * Compute the year from extended year. + * @internal + */ + int32_t extendedYearToYear(int32_t extendedYear) const override; +- +- /** +- * @internal +- */ +- bool isEra0CountingBackward() const override; + public: + /** + * Override Calendar Returns a unique class ID POLYMORPHICALLY. Pure virtual + * override. This method is to implement a simple version of RTTI, since not all C++ + * compilers support genuine RTTI. Polymorphic operator==() and clone() methods call + * this method. + * + * @return The class ID for this object. All objects of a given class have the diff --git a/gnu/packages/patches/icu4c-suppress-warnings.patch b/gnu/packages/patches/icu4c-suppress-warnings.patch new file mode 100644 index 00000000000..e8c3e34b4a4 --- /dev/null +++ b/gnu/packages/patches/icu4c-suppress-warnings.patch @@ -0,0 +1,80 @@ +diff --git a/source/acinclude.m4 b/source/acinclude.m4 +--- a/source/acinclude.m4 ++++ b/source/acinclude.m4 +@@ -459,30 +459,36 @@ AC_DEFUN([AC_CHECK_STRICT_COMPILE], + ], [ac_use_strict_options=yes]) + AC_MSG_RESULT($ac_use_strict_options) + + if test "$ac_use_strict_options" = yes + then + if test "$GCC" = yes + then + CFLAGS="$CFLAGS -Wall -pedantic -Wshadow -Wpointer-arith -Wmissing-prototypes -Wwrite-strings" ++ ++ # Suppress clang C warnings: ++ CFLAGS="$CFLAGS -Wno-sign-compare -Wno-unused" + else + case "${host}" in + *-*-cygwin) + if test "`$CC /help 2>&1 | head -c9`" = "Microsoft" + then + CFLAGS="$CFLAGS /W4" + fi ;; + *-*-mingw*) + CFLAGS="$CFLAGS -W4" ;; + esac + fi + if test "$GXX" = yes + then + CXXFLAGS="$CXXFLAGS -W -Wall -pedantic -Wpointer-arith -Wwrite-strings -Wno-long-long" ++ ++ # Suppress clang C++ warnings: ++ CXXFLAGS="$CXXFLAGS -Wno-unused -Wno-unused-parameter" + else + case "${host}" in + *-*-cygwin) + if test "`$CXX /help 2>&1 | head -c9`" = "Microsoft" + then + CXXFLAGS="$CXXFLAGS /W4" + fi ;; + *-*-mingw*) +diff --git a/source/configure b/source/configure +--- a/source/configure ++++ b/source/configure +@@ -5227,30 +5227,36 @@ fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_use_strict_options" >&5 + printf "%s\n" "$ac_use_strict_options" >&6; } + + if test "$ac_use_strict_options" = yes + then + if test "$GCC" = yes + then + CFLAGS="$CFLAGS -Wall -pedantic -Wshadow -Wpointer-arith -Wmissing-prototypes -Wwrite-strings" ++ ++ # Suppress clang C warnings: ++ CFLAGS="$CFLAGS -Wno-sign-compare -Wno-unused" + else + case "${host}" in + *-*-cygwin) + if test "`$CC /help 2>&1 | head -c9`" = "Microsoft" + then + CFLAGS="$CFLAGS /W4" + fi ;; + *-*-mingw*) + CFLAGS="$CFLAGS -W4" ;; + esac + fi + if test "$GXX" = yes + then + CXXFLAGS="$CXXFLAGS -W -Wall -pedantic -Wpointer-arith -Wwrite-strings -Wno-long-long" ++ ++ # Suppress clang C++ warnings: ++ CXXFLAGS="$CXXFLAGS -Wno-unused -Wno-unused-parameter" + else + case "${host}" in + *-*-cygwin) + if test "`$CXX /help 2>&1 | head -c9`" = "Microsoft" + then + CXXFLAGS="$CXXFLAGS /W4" + fi ;; + *-*-mingw*)