diff --git a/tools/icu/patches/75/source/common/unicode/platform.h b/tools/icu/patches/75/source/common/unicode/platform.h new file mode 100644 index 00000000000000..59176005f334b1 --- /dev/null +++ b/tools/icu/patches/75/source/common/unicode/platform.h @@ -0,0 +1,849 @@ +// © 2016 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html +/* +****************************************************************************** +* +* Copyright (C) 1997-2016, International Business Machines +* Corporation and others. All Rights Reserved. +* +****************************************************************************** +* +* FILE NAME : platform.h +* +* Date Name Description +* 05/13/98 nos Creation (content moved here from ptypes.h). +* 03/02/99 stephen Added AS400 support. +* 03/30/99 stephen Added Linux support. +* 04/13/99 stephen Reworked for autoconf. +****************************************************************************** +*/ + +#ifndef _PLATFORM_H +#define _PLATFORM_H + +#include "unicode/uconfig.h" +#include "unicode/uvernum.h" + +/** + * \file + * \brief Basic types for the platform. + * + * This file used to be generated by autoconf/configure. + * Starting with ICU 49, platform.h is a normal source file, + * to simplify cross-compiling and working with non-autoconf/make build systems. + * + * When a value in this file does not work on a platform, then please + * try to derive it from the U_PLATFORM value + * (for which we might need a new value constant in rare cases) + * and/or from other macros that are predefined by the compiler + * or defined in standard (POSIX or platform or compiler) headers. + * + * As a temporary workaround, you can add an explicit \#define for some macros + * before it is first tested, or add an equivalent -D macro definition + * to the compiler's command line. + * + * Note: Some compilers provide ways to show the predefined macros. + * For example, with gcc you can compile an empty .c file and have the compiler + * print the predefined macros with + * \code + * gcc -E -dM -x c /dev/null | sort + * \endcode + * (You can provide an actual empty .c file rather than /dev/null. + * -x c++ is for C++.) + */ + +/** + * Define some things so that they can be documented. + * @internal + */ +#ifdef U_IN_DOXYGEN +/* + * Problem: "platform.h:335: warning: documentation for unknown define U_HAVE_STD_STRING found." means that U_HAVE_STD_STRING is not documented. + * Solution: #define any defines for non @internal API here, so that they are visible in the docs. If you just set PREDEFINED in Doxyfile.in, they won't be documented. + */ + +/* None for now. */ +#endif + +/** + * \def U_PLATFORM + * The U_PLATFORM macro defines the platform we're on. + * + * We used to define one different, value-less macro per platform. + * That made it hard to know the set of relevant platforms and macros, + * and hard to deal with variants of platforms. + * + * Starting with ICU 49, we define platforms as numeric macros, + * with ranges of values for related platforms and their variants. + * The U_PLATFORM macro is set to one of these values. + * + * Historical note from the Solaris Wikipedia article: + * AT&T and Sun collaborated on a project to merge the most popular Unix variants + * on the market at that time: BSD, System V, and Xenix. + * This became Unix System V Release 4 (SVR4). + * + * @internal + */ + +/** Unknown platform. @internal */ +#define U_PF_UNKNOWN 0 +/** Windows @internal */ +#define U_PF_WINDOWS 1000 +/** MinGW. Windows, calls to Win32 API, but using GNU gcc and binutils. @internal */ +#define U_PF_MINGW 1800 +/** + * Cygwin. Windows, calls to cygwin1.dll for Posix functions, + * using MSVC or GNU gcc and binutils. + * @internal + */ +#define U_PF_CYGWIN 1900 +/* Reserve 2000 for U_PF_UNIX? */ +/** HP-UX is based on UNIX System V. @internal */ +#define U_PF_HPUX 2100 +/** Solaris is a Unix operating system based on SVR4. @internal */ +#define U_PF_SOLARIS 2600 +/** BSD is a UNIX operating system derivative. @internal */ +#define U_PF_BSD 3000 +/** AIX is based on UNIX System V Releases and 4.3 BSD. @internal */ +#define U_PF_AIX 3100 +/** IRIX is based on UNIX System V with BSD extensions. @internal */ +#define U_PF_IRIX 3200 +/** + * Darwin is a POSIX-compliant operating system, composed of code developed by Apple, + * as well as code derived from NeXTSTEP, BSD, and other projects, + * built around the Mach kernel. + * Darwin forms the core set of components upon which Mac OS X, Apple TV, and iOS are based. + * (Original description modified from WikiPedia.) + * @internal + */ +#define U_PF_DARWIN 3500 +/** iPhone OS (iOS) is a derivative of Mac OS X. @internal */ +#define U_PF_IPHONE 3550 +/** QNX is a commercial Unix-like real-time operating system related to BSD. @internal */ +#define U_PF_QNX 3700 +/** Linux is a Unix-like operating system. @internal */ +#define U_PF_LINUX 4000 +/** + * Native Client is pretty close to Linux. + * See https://developer.chrome.com/native-client and + * http://www.chromium.org/nativeclient + * @internal + */ +#define U_PF_BROWSER_NATIVE_CLIENT 4020 +/** Android is based on Linux. @internal */ +#define U_PF_ANDROID 4050 +/** Fuchsia is a POSIX-ish platform. @internal */ +#define U_PF_FUCHSIA 4100 +/* Maximum value for Linux-based platform is 4499 */ +/** + * Emscripten is a C++ transpiler for the Web that can target asm.js or + * WebAssembly. It provides some POSIX-compatible wrappers and stubs and + * some Linux-like functionality, but is not fully compatible with + * either. + * @internal + */ +#define U_PF_EMSCRIPTEN 5010 +/** z/OS is the successor to OS/390 which was the successor to MVS. @internal */ +#define U_PF_OS390 9000 +/** "IBM i" is the current name of what used to be i5/OS and earlier OS/400. @internal */ +#define U_PF_OS400 9400 + +#ifdef U_PLATFORM + /* Use the predefined value. */ +#elif defined(__MINGW32__) +# define U_PLATFORM U_PF_MINGW +#elif defined(__CYGWIN__) +# define U_PLATFORM U_PF_CYGWIN +#elif defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) +# define U_PLATFORM U_PF_WINDOWS +#elif defined(__ANDROID__) +# define U_PLATFORM U_PF_ANDROID + /* Android wchar_t support depends on the API level. */ +# include +#elif defined(__pnacl__) || defined(__native_client__) +# define U_PLATFORM U_PF_BROWSER_NATIVE_CLIENT +#elif defined(__Fuchsia__) +# define U_PLATFORM U_PF_FUCHSIA +#elif defined(linux) || defined(__linux__) || defined(__linux) +# define U_PLATFORM U_PF_LINUX +#elif defined(__APPLE__) && defined(__MACH__) +# include +# if (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && (defined(TARGET_OS_MACCATALYST) && !TARGET_OS_MACCATALYST) /* variant of TARGET_OS_MAC */ +# define U_PLATFORM U_PF_IPHONE +# else +# define U_PLATFORM U_PF_DARWIN +# endif +#elif defined(BSD) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__MirBSD__) +# if defined(__FreeBSD__) +# include +# endif +# define U_PLATFORM U_PF_BSD +#elif defined(sun) || defined(__sun) + /* Check defined(__SVR4) || defined(__svr4__) to distinguish Solaris from SunOS? */ +# define U_PLATFORM U_PF_SOLARIS +# if defined(__GNUC__) + /* Solaris/GCC needs this header file to get the proper endianness. Normally, this + * header file is included with stddef.h but on Solairs/GCC, the GCC version of stddef.h + * is included which does not include this header file. + */ +# include +# endif +#elif defined(_AIX) || defined(__TOS_AIX__) +# define U_PLATFORM U_PF_AIX +#elif defined(_hpux) || defined(hpux) || defined(__hpux) +# define U_PLATFORM U_PF_HPUX +#elif defined(sgi) || defined(__sgi) +# define U_PLATFORM U_PF_IRIX +#elif defined(__QNX__) || defined(__QNXNTO__) +# define U_PLATFORM U_PF_QNX +#elif defined(__TOS_MVS__) +# define U_PLATFORM U_PF_OS390 +#elif defined(__OS400__) || defined(__TOS_OS400__) +# define U_PLATFORM U_PF_OS400 +#elif defined(__EMSCRIPTEN__) +# define U_PLATFORM U_PF_EMSCRIPTEN +#else +# define U_PLATFORM U_PF_UNKNOWN +#endif + +/** + * \def U_REAL_MSVC + * Defined if the compiler is the real MSVC compiler (and not something like + * Clang setting _MSC_VER in order to compile Windows code that requires it). + * Otherwise undefined. + * @internal + */ +#if (defined(_MSC_VER) && !(defined(__clang__) && __clang__)) || defined(U_IN_DOXYGEN) +# define U_REAL_MSVC +#endif + +/** + * \def CYGWINMSVC + * Defined if this is Windows with Cygwin, but using MSVC rather than gcc. + * Otherwise undefined. + * @internal + */ +/* Commented out because this is already set in mh-cygwin-msvc +#if U_PLATFORM == U_PF_CYGWIN && defined(_MSC_VER) +# define CYGWINMSVC +#endif +*/ +#ifdef U_IN_DOXYGEN +# define CYGWINMSVC +#endif + +/** + * \def U_PLATFORM_USES_ONLY_WIN32_API + * Defines whether the platform uses only the Win32 API. + * Set to 1 for Windows/MSVC, ClangCL and MinGW but not Cygwin. + * @internal + */ +#ifdef U_PLATFORM_USES_ONLY_WIN32_API + /* Use the predefined value. */ +#elif (U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_MINGW) || defined(CYGWINMSVC) +# define U_PLATFORM_USES_ONLY_WIN32_API 1 +#else + /* Cygwin implements POSIX. */ +# define U_PLATFORM_USES_ONLY_WIN32_API 0 +#endif + +/** + * \def U_PLATFORM_HAS_WIN32_API + * Defines whether the Win32 API is available on the platform. + * Set to 1 for Windows/MSVC, ClangCL, MinGW and Cygwin. + * @internal + */ +#ifdef U_PLATFORM_HAS_WIN32_API + /* Use the predefined value. */ +#elif U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN +# define U_PLATFORM_HAS_WIN32_API 1 +#else +# define U_PLATFORM_HAS_WIN32_API 0 +#endif + +/** + * \def U_PLATFORM_HAS_WINUWP_API + * Defines whether target is intended for Universal Windows Platform API + * Set to 1 for Windows10 Release Solution Configuration + * @internal + */ +#ifdef U_PLATFORM_HAS_WINUWP_API + /* Use the predefined value. */ +#else +# define U_PLATFORM_HAS_WINUWP_API 0 +#endif + +/** + * \def U_PLATFORM_IMPLEMENTS_POSIX + * Defines whether the platform implements (most of) the POSIX API. + * Set to 1 for Cygwin and most other platforms. + * @internal + */ +#ifdef U_PLATFORM_IMPLEMENTS_POSIX + /* Use the predefined value. */ +#elif U_PLATFORM_USES_ONLY_WIN32_API +# define U_PLATFORM_IMPLEMENTS_POSIX 0 +#else +# define U_PLATFORM_IMPLEMENTS_POSIX 1 +#endif + +/** + * \def U_PLATFORM_IS_LINUX_BASED + * Defines whether the platform is Linux or one of its derivatives. + * @internal + */ +#ifdef U_PLATFORM_IS_LINUX_BASED + /* Use the predefined value. */ +#elif U_PF_LINUX <= U_PLATFORM && U_PLATFORM <= 4499 +# define U_PLATFORM_IS_LINUX_BASED 1 +#else +# define U_PLATFORM_IS_LINUX_BASED 0 +#endif + +/** + * \def U_PLATFORM_IS_DARWIN_BASED + * Defines whether the platform is Darwin or one of its derivatives. + * @internal + */ +#ifdef U_PLATFORM_IS_DARWIN_BASED + /* Use the predefined value. */ +#elif U_PF_DARWIN <= U_PLATFORM && U_PLATFORM <= U_PF_IPHONE +# define U_PLATFORM_IS_DARWIN_BASED 1 +#else +# define U_PLATFORM_IS_DARWIN_BASED 0 +#endif + +/*===========================================================================*/ +/** @{ Compiler and environment features */ +/*===========================================================================*/ + +/** + * \def U_GCC_MAJOR_MINOR + * Indicates whether the compiler is gcc (test for != 0), + * and if so, contains its major (times 100) and minor version numbers. + * If the compiler is not gcc, then U_GCC_MAJOR_MINOR == 0. + * + * For example, for testing for whether we have gcc, and whether it's 4.6 or higher, + * use "#if U_GCC_MAJOR_MINOR >= 406". + * @internal + */ +#ifdef __GNUC__ +# define U_GCC_MAJOR_MINOR (__GNUC__ * 100 + __GNUC_MINOR__) +#else +# define U_GCC_MAJOR_MINOR 0 +#endif + +/** + * \def U_IS_BIG_ENDIAN + * Determines the endianness of the platform. + * @internal + */ +#ifdef U_IS_BIG_ENDIAN + /* Use the predefined value. */ +#elif defined(BYTE_ORDER) && defined(BIG_ENDIAN) +# define U_IS_BIG_ENDIAN (BYTE_ORDER == BIG_ENDIAN) +#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) + /* gcc */ +# define U_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#elif defined(__BIG_ENDIAN__) || defined(_BIG_ENDIAN) +# define U_IS_BIG_ENDIAN 1 +#elif defined(__LITTLE_ENDIAN__) || defined(_LITTLE_ENDIAN) +# define U_IS_BIG_ENDIAN 0 +#elif U_PLATFORM == U_PF_OS390 || U_PLATFORM == U_PF_OS400 || defined(__s390__) || defined(__s390x__) + /* These platforms do not appear to predefine any endianness macros. */ +# define U_IS_BIG_ENDIAN 1 +#elif defined(_PA_RISC1_0) || defined(_PA_RISC1_1) || defined(_PA_RISC2_0) + /* HPPA do not appear to predefine any endianness macros. */ +# define U_IS_BIG_ENDIAN 1 +#elif defined(sparc) || defined(__sparc) || defined(__sparc__) + /* Some sparc based systems (e.g. Linux) do not predefine any endianness macros. */ +# define U_IS_BIG_ENDIAN 1 +#else +# define U_IS_BIG_ENDIAN 0 +#endif + +/** + * \def U_HAVE_PLACEMENT_NEW + * Determines whether to override placement new and delete for STL. + * @stable ICU 2.6 + */ +#ifdef U_HAVE_PLACEMENT_NEW + /* Use the predefined value. */ +#elif defined(__BORLANDC__) +# define U_HAVE_PLACEMENT_NEW 0 +#else +# define U_HAVE_PLACEMENT_NEW 1 +#endif + +/** + * \def U_HAVE_DEBUG_LOCATION_NEW + * Define this to define the MFC debug version of the operator new. + * + * @stable ICU 3.4 + */ +#ifdef U_HAVE_DEBUG_LOCATION_NEW + /* Use the predefined value. */ +#elif defined(_MSC_VER) +# define U_HAVE_DEBUG_LOCATION_NEW 1 +#else +# define U_HAVE_DEBUG_LOCATION_NEW 0 +#endif + +/* Compatibility with compilers other than clang: http://clang.llvm.org/docs/LanguageExtensions.html */ +#ifdef __has_attribute +# define UPRV_HAS_ATTRIBUTE(x) __has_attribute(x) +#else +# define UPRV_HAS_ATTRIBUTE(x) 0 +#endif +#ifdef __has_cpp_attribute +# define UPRV_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define UPRV_HAS_CPP_ATTRIBUTE(x) 0 +#endif +#ifdef __has_declspec_attribute +# define UPRV_HAS_DECLSPEC_ATTRIBUTE(x) __has_declspec_attribute(x) +#else +# define UPRV_HAS_DECLSPEC_ATTRIBUTE(x) 0 +#endif +#ifdef __has_builtin +# define UPRV_HAS_BUILTIN(x) __has_builtin(x) +#else +# define UPRV_HAS_BUILTIN(x) 0 +#endif +#ifdef __has_feature +# define UPRV_HAS_FEATURE(x) __has_feature(x) +#else +# define UPRV_HAS_FEATURE(x) 0 +#endif +#ifdef __has_extension +# define UPRV_HAS_EXTENSION(x) __has_extension(x) +#else +# define UPRV_HAS_EXTENSION(x) 0 +#endif +#ifdef __has_warning +# define UPRV_HAS_WARNING(x) __has_warning(x) +#else +# define UPRV_HAS_WARNING(x) 0 +#endif + + +#if defined(__clang__) +#define UPRV_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize("undefined"))) +#else +#define UPRV_NO_SANITIZE_UNDEFINED +#endif + +/** + * \def U_MALLOC_ATTR + * Attribute to mark functions as malloc-like + * @internal + */ +#if defined(__GNUC__) && __GNUC__>=3 +# define U_MALLOC_ATTR __attribute__ ((__malloc__)) +#else +# define U_MALLOC_ATTR +#endif + +/** + * \def U_ALLOC_SIZE_ATTR + * Attribute to specify the size of the allocated buffer for malloc-like functions + * @internal + */ +#if (defined(__GNUC__) && \ + (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) || \ + UPRV_HAS_ATTRIBUTE(alloc_size) +# define U_ALLOC_SIZE_ATTR(X) __attribute__ ((alloc_size(X))) +# define U_ALLOC_SIZE_ATTR2(X,Y) __attribute__ ((alloc_size(X,Y))) +#else +# define U_ALLOC_SIZE_ATTR(X) +# define U_ALLOC_SIZE_ATTR2(X,Y) +#endif + +/** + * \def U_CPLUSPLUS_VERSION + * 0 if no C++; 1, 11, 14, ... if C++. + * Support for specific features cannot always be determined by the C++ version alone. + * @internal + */ +#ifdef U_CPLUSPLUS_VERSION +# if U_CPLUSPLUS_VERSION != 0 && !defined(__cplusplus) +# undef U_CPLUSPLUS_VERSION +# define U_CPLUSPLUS_VERSION 0 +# endif + /* Otherwise use the predefined value. */ +#elif !defined(__cplusplus) +# define U_CPLUSPLUS_VERSION 0 +#elif __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +# define U_CPLUSPLUS_VERSION 17 +#elif __cplusplus >= 201402L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) +# define U_CPLUSPLUS_VERSION 14 +#elif __cplusplus >= 201103L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201103L) +# define U_CPLUSPLUS_VERSION 11 +#else + // C++98 or C++03 +# define U_CPLUSPLUS_VERSION 1 +#endif + +/** + * \def U_FALLTHROUGH + * Annotate intentional fall-through between switch labels. + * http://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough + * @internal + */ +#ifndef __cplusplus + // Not for C. +#elif defined(U_FALLTHROUGH) + // Use the predefined value. +#elif defined(__clang__) + // Test for compiler vs. feature separately. + // Other compilers might choke on the feature test. +# if UPRV_HAS_CPP_ATTRIBUTE(clang::fallthrough) || \ + (UPRV_HAS_FEATURE(cxx_attributes) && \ + UPRV_HAS_WARNING("-Wimplicit-fallthrough")) +# define U_FALLTHROUGH [[clang::fallthrough]] +# endif +#elif defined(__GNUC__) && (__GNUC__ >= 7) +# define U_FALLTHROUGH __attribute__((fallthrough)) +#endif + +#ifndef U_FALLTHROUGH +# define U_FALLTHROUGH +#endif + +/** @} */ + +/*===========================================================================*/ +/** @{ Character data types */ +/*===========================================================================*/ + +/** + * U_CHARSET_FAMILY is equal to this value when the platform is an ASCII based platform. + * @stable ICU 2.0 + */ +#define U_ASCII_FAMILY 0 + +/** + * U_CHARSET_FAMILY is equal to this value when the platform is an EBCDIC based platform. + * @stable ICU 2.0 + */ +#define U_EBCDIC_FAMILY 1 + +/** + * \def U_CHARSET_FAMILY + * + *

These definitions allow to specify the encoding of text + * in the char data type as defined by the platform and the compiler. + * It is enough to determine the code point values of "invariant characters", + * which are the ones shared by all encodings that are in use + * on a given platform.

+ * + *

Those "invariant characters" should be all the uppercase and lowercase + * latin letters, the digits, the space, and "basic punctuation". + * Also, '\\n', '\\r', '\\t' should be available.

+ * + *

The list of "invariant characters" is:
+ * \code + * A-Z a-z 0-9 SPACE " % & ' ( ) * + , - . / : ; < = > ? _ + * \endcode + *
+ * (52 letters + 10 numbers + 20 punc/sym/space = 82 total)

+ * + *

This matches the IBM Syntactic Character Set (CS 640).

+ * + *

In other words, all the graphic characters in 7-bit ASCII should + * be safely accessible except the following:

+ * + * \code + * '\' + * '[' + * ']' + * '{' + * '}' + * '^' + * '~' + * '!' + * '#' + * '|' + * '$' + * '@' + * '`' + * \endcode + * @stable ICU 2.0 + */ +#ifdef U_CHARSET_FAMILY + /* Use the predefined value. */ +#elif U_PLATFORM == U_PF_OS390 && (!defined(__CHARSET_LIB) || !__CHARSET_LIB) +# define U_CHARSET_FAMILY U_EBCDIC_FAMILY +#elif U_PLATFORM == U_PF_OS400 && !defined(__UTF32__) +# define U_CHARSET_FAMILY U_EBCDIC_FAMILY +#else +# define U_CHARSET_FAMILY U_ASCII_FAMILY +#endif + +/** + * \def U_CHARSET_IS_UTF8 + * + * Hardcode the default charset to UTF-8. + * + * If this is set to 1, then + * - ICU will assume that all non-invariant char*, StringPiece, std::string etc. + * contain UTF-8 text, regardless of what the system API uses + * - some ICU code will use fast functions like u_strFromUTF8() + * rather than the more general and more heavy-weight conversion API (ucnv.h) + * - ucnv_getDefaultName() always returns "UTF-8" + * - ucnv_setDefaultName() is disabled and will not change the default charset + * - static builds of ICU are smaller + * - more functionality is available with the UCONFIG_NO_CONVERSION build-time + * configuration option (see unicode/uconfig.h) + * - the UCONFIG_NO_CONVERSION build option in uconfig.h is more usable + * + * @stable ICU 4.2 + * @see UCONFIG_NO_CONVERSION + */ +#ifdef U_CHARSET_IS_UTF8 + /* Use the predefined value. */ +#elif U_PLATFORM_IS_LINUX_BASED || U_PLATFORM_IS_DARWIN_BASED || \ + U_PLATFORM == U_PF_EMSCRIPTEN +# define U_CHARSET_IS_UTF8 1 +#else +# define U_CHARSET_IS_UTF8 0 +#endif + +/** @} */ + +/*===========================================================================*/ +/** @{ Information about wchar support */ +/*===========================================================================*/ + +/** + * \def U_HAVE_WCHAR_H + * Indicates whether is available (1) or not (0). Set to 1 by default. + * + * @stable ICU 2.0 + */ +#ifdef U_HAVE_WCHAR_H + /* Use the predefined value. */ +#elif U_PLATFORM == U_PF_ANDROID && __ANDROID_API__ < 9 + /* + * Android before Gingerbread (Android 2.3, API level 9) did not support wchar_t. + * The type and header existed, but the library functions did not work as expected. + * The size of wchar_t was 1 but L"xyz" string literals had 32-bit units anyway. + */ +# define U_HAVE_WCHAR_H 0 +#else +# define U_HAVE_WCHAR_H 1 +#endif + +/** + * \def U_SIZEOF_WCHAR_T + * U_SIZEOF_WCHAR_T==sizeof(wchar_t) + * + * @stable ICU 2.0 + */ +#ifdef U_SIZEOF_WCHAR_T + /* Use the predefined value. */ +#elif (U_PLATFORM == U_PF_ANDROID && __ANDROID_API__ < 9) + /* + * Classic Mac OS and Mac OS X before 10.3 (Panther) did not support wchar_t or wstring. + * Newer Mac OS X has size 4. + */ +# define U_SIZEOF_WCHAR_T 1 +#elif U_PLATFORM_HAS_WIN32_API || U_PLATFORM == U_PF_CYGWIN +# define U_SIZEOF_WCHAR_T 2 +#elif U_PLATFORM == U_PF_AIX + /* + * AIX 6.1 information, section "Wide character data representation": + * "... the wchar_t datatype is 32-bit in the 64-bit environment and + * 16-bit in the 32-bit environment." + * and + * "All locales use Unicode for their wide character code values (process code), + * except the IBM-eucTW codeset." + */ +# ifdef __64BIT__ +# define U_SIZEOF_WCHAR_T 4 +# else +# define U_SIZEOF_WCHAR_T 2 +# endif +#elif U_PLATFORM == U_PF_OS390 + /* + * z/OS V1R11 information center, section "LP64 | ILP32": + * "In 31-bit mode, the size of long and pointers is 4 bytes and the size of wchar_t is 2 bytes. + * Under LP64, the size of long and pointer is 8 bytes and the size of wchar_t is 4 bytes." + */ +# ifdef _LP64 +# define U_SIZEOF_WCHAR_T 4 +# else +# define U_SIZEOF_WCHAR_T 2 +# endif +#elif U_PLATFORM == U_PF_OS400 +# if defined(__UTF32__) + /* + * LOCALETYPE(*LOCALEUTF) is specified. + * Wide-character strings are in UTF-32, + * narrow-character strings are in UTF-8. + */ +# define U_SIZEOF_WCHAR_T 4 +# elif defined(__UCS2__) + /* + * LOCALETYPE(*LOCALEUCS2) is specified. + * Wide-character strings are in UCS-2, + * narrow-character strings are in EBCDIC. + */ +# define U_SIZEOF_WCHAR_T 2 +# else + /* + * LOCALETYPE(*CLD) or LOCALETYPE(*LOCALE) is specified. + * Wide-character strings are in 16-bit EBCDIC, + * narrow-character strings are in EBCDIC. + */ +# define U_SIZEOF_WCHAR_T 2 +# endif +#else +# define U_SIZEOF_WCHAR_T 4 +#endif + +#ifndef U_HAVE_WCSCPY +#define U_HAVE_WCSCPY U_HAVE_WCHAR_H +#endif + +/** @} */ + +/** + * \def U_HAVE_CHAR16_T + * Defines whether the char16_t type is available for UTF-16 + * and u"abc" UTF-16 string literals are supported. + * This is a new standard type and standard string literal syntax in C++11 + * but has been available in some compilers before. + * @internal + */ +#ifdef U_HAVE_CHAR16_T + /* Use the predefined value. */ +#else + /* + * Notes: + * C++11 and C11 require support for UTF-16 literals + * Doesn't work on Mac C11 (see workaround in ptypes.h). + */ +# if defined(__cplusplus) || !U_PLATFORM_IS_DARWIN_BASED +# define U_HAVE_CHAR16_T 1 +# else +# define U_HAVE_CHAR16_T 0 +# endif +#endif + +/** + * @{ + * \def U_DECLARE_UTF16 + * Do not use this macro because it is not defined on all platforms. + * Use the UNICODE_STRING or U_STRING_DECL macros instead. + * @internal + */ +#ifdef U_DECLARE_UTF16 + /* Use the predefined value. */ +#elif U_HAVE_CHAR16_T \ + || (defined(__xlC__) && defined(__IBM_UTF_LITERAL) && U_SIZEOF_WCHAR_T != 2) \ + || (defined(__HP_aCC) && __HP_aCC >= 035000) \ + || (defined(__HP_cc) && __HP_cc >= 111106) \ + || (defined(U_IN_DOXYGEN)) +# define U_DECLARE_UTF16(string) u ## string +#elif U_SIZEOF_WCHAR_T == 2 \ + && (U_CHARSET_FAMILY == 0 || (U_PF_OS390 <= U_PLATFORM && U_PLATFORM <= U_PF_OS400 && defined(__UCS2__))) +# define U_DECLARE_UTF16(string) L ## string +#else + /* Leave U_DECLARE_UTF16 undefined. See unistr.h. */ +#endif + +/** @} */ + +/*===========================================================================*/ +/** @{ Symbol import-export control */ +/*===========================================================================*/ + +#ifdef U_EXPORT + /* Use the predefined value. */ +#elif defined(U_STATIC_IMPLEMENTATION) +# define U_EXPORT +#elif defined(_MSC_VER) || (UPRV_HAS_DECLSPEC_ATTRIBUTE(__dllexport__) && \ + UPRV_HAS_DECLSPEC_ATTRIBUTE(__dllimport__)) +# define U_EXPORT __declspec(dllexport) +#elif defined(__GNUC__) +# define U_EXPORT __attribute__((visibility("default"))) +#elif (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x550) \ + || (defined(__SUNPRO_C) && __SUNPRO_C >= 0x550) +# define U_EXPORT __global +/*#elif defined(__HP_aCC) || defined(__HP_cc) +# define U_EXPORT __declspec(dllexport)*/ +#else +# define U_EXPORT +#endif + +/* U_CALLCONV is related to U_EXPORT2 */ +#ifdef U_EXPORT2 + /* Use the predefined value. */ +#elif defined(_MSC_VER) +# define U_EXPORT2 __cdecl +#else +# define U_EXPORT2 +#endif + +#ifdef U_IMPORT + /* Use the predefined value. */ +#elif defined(_MSC_VER) || (UPRV_HAS_DECLSPEC_ATTRIBUTE(__dllexport__) && \ + UPRV_HAS_DECLSPEC_ATTRIBUTE(__dllimport__)) + /* Windows needs to export/import data. */ +# define U_IMPORT __declspec(dllimport) +#else +# define U_IMPORT +#endif + +/** + * \def U_HIDDEN + * This is used to mark internal structs declared within external classes, + * to prevent the internal structs from having the same visibility as the + * class within which they are declared. + * @internal + */ +#ifdef U_HIDDEN + /* Use the predefined value. */ +#elif defined(__GNUC__) +# define U_HIDDEN __attribute__((visibility("hidden"))) +#else +# define U_HIDDEN +#endif + +/** + * \def U_CALLCONV + * Similar to U_CDECL_BEGIN/U_CDECL_END, this qualifier is necessary + * in callback function typedefs to make sure that the calling convention + * is compatible. + * + * This is only used for non-ICU-API functions. + * When a function is a public ICU API, + * you must use the U_CAPI and U_EXPORT2 qualifiers. + * + * Please note, you need to use U_CALLCONV after the *. + * + * NO : "static const char U_CALLCONV *func( . . . )" + * YES: "static const char* U_CALLCONV func( . . . )" + * + * @stable ICU 2.0 + */ +#if U_PLATFORM == U_PF_OS390 && defined(__cplusplus) +# define U_CALLCONV __cdecl +#else +# define U_CALLCONV U_EXPORT2 +#endif + +/** + * \def U_CALLCONV_FPTR + * Similar to U_CALLCONV, but only used on function pointers. + * @internal + */ +#if U_PLATFORM == U_PF_OS390 && defined(__cplusplus) +# define U_CALLCONV_FPTR U_CALLCONV +#else +# define U_CALLCONV_FPTR +#endif +/** @} */ + +#endif // _PLATFORM_H diff --git a/tools/icu/patches/75/source/tools/genccode/genccode.c b/tools/icu/patches/75/source/tools/genccode/genccode.c new file mode 100644 index 00000000000000..0f243952a7d452 --- /dev/null +++ b/tools/icu/patches/75/source/tools/genccode/genccode.c @@ -0,0 +1,226 @@ +// © 2016 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html +/* + ******************************************************************************* + * Copyright (C) 1999-2016, International Business Machines + * Corporation and others. All Rights Reserved. + ******************************************************************************* + * file name: gennames.c + * encoding: UTF-8 + * tab size: 8 (not used) + * indentation:4 + * + * created on: 1999nov01 + * created by: Markus W. Scherer + * + * This program reads a binary file and creates a C source code file + * with a byte array that contains the data of the binary file. + * + * 12/09/1999 weiv Added multiple file handling + */ + +#include "unicode/utypes.h" + +#if U_PLATFORM_HAS_WIN32_API +# define VC_EXTRALEAN +# define WIN32_LEAN_AND_MEAN +# define NOUSER +# define NOSERVICE +# define NOIME +# define NOMCX +#include +#include +#endif + +#if U_PLATFORM_IS_LINUX_BASED && U_HAVE_ELF_H +# define U_ELF +#endif + +#ifdef U_ELF +# include +# 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 +#include +#include +#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" + +enum { + kOptHelpH = 0, + kOptHelpQuestionMark, + kOptDestDir, + kOptQuiet, + kOptName, + kOptEntryPoint, +#ifdef CAN_GENERATE_OBJECTS + kOptObject, + kOptMatchArch, + kOptCpuArch, + kOptSkipDllExport, +#endif + kOptFilename, + kOptAssembly +}; + +static UOption options[]={ +/*0*/UOPTION_HELP_H, + UOPTION_HELP_QUESTION_MARK, + UOPTION_DESTDIR, + UOPTION_QUIET, + UOPTION_DEF("name", 'n', UOPT_REQUIRES_ARG), + UOPTION_DEF("entrypoint", 'e', UOPT_REQUIRES_ARG), +#ifdef CAN_GENERATE_OBJECTS +/*6*/UOPTION_DEF("object", 'o', UOPT_NO_ARG), + UOPTION_DEF("match-arch", 'm', UOPT_REQUIRES_ARG), + UOPTION_DEF("cpu-arch", 'c', UOPT_REQUIRES_ARG), + UOPTION_DEF("skip-dll-export", '\0', UOPT_NO_ARG), +#endif + UOPTION_DEF("filename", 'f', UOPT_REQUIRES_ARG), + UOPTION_DEF("assembly", 'a', UOPT_REQUIRES_ARG) +}; + +#define CALL_WRITECCODE 'c' +#define CALL_WRITEASSEMBLY 'a' +#define CALL_WRITEOBJECT 'o' +extern int +main(int argc, char* argv[]) { + UBool verbose = true; + char writeCode; + + U_MAIN_INIT_ARGS(argc, argv); + + options[kOptDestDir].value = "."; + + /* read command line options */ + argc=u_parseArgs(argc, argv, UPRV_LENGTHOF(options), options); + + /* error handling, printing usage message */ + if(argc<0) { + fprintf(stderr, + "error in command line argument \"%s\"\n", + argv[-argc]); + } + if(argc<0 || options[kOptHelpH].doesOccur || options[kOptHelpQuestionMark].doesOccur) { + fprintf(stderr, + "usage: %s [-options] filename1 filename2 ...\n" + "\tread each binary input file and \n" + "\tcreate a .c file with a byte array that contains the input file's data\n" + "options:\n" + "\t-h or -? or --help this usage text\n" + "\t-d or --destdir destination directory, followed by the path\n" + "\t-q or --quiet do not display warnings and progress\n" + "\t-n or --name symbol prefix, followed by the prefix\n" + "\t-e or --entrypoint entry point name, followed by the name (_dat will be appended)\n" + "\t-r or --revision Specify a version\n" + , argv[0]); +#ifdef CAN_GENERATE_OBJECTS + fprintf(stderr, + "\t-o or --object write a .obj file instead of .c\n" + "\t-m or --match-arch file.o match the architecture (CPU, 32/64 bits) of the specified .o\n" + "\t ELF format defaults to i386. Windows defaults to the native platform.\n" + "\t-c or --cpu-arch Specify a CPU architecture for which to write a .obj file for ClangCL on Windows\n" + "\t Valid values for this opton are x64, x86 and arm64.\n" + "\t--skip-dll-export Don't export the ICU data entry point symbol (for use when statically linking)\n"); +#endif + fprintf(stderr, + "\t-f or --filename Specify an alternate base filename. (default: symbolname_typ)\n" + "\t-a or --assembly Create assembly file. (possible values are: "); + + printAssemblyHeadersToStdErr(); + } else { + const char *message, *filename; + /* TODO: remove void (*writeCode)(const char *, const char *); */ + + if(options[kOptAssembly].doesOccur) { + message="generating assembly code for %s\n"; + writeCode = CALL_WRITEASSEMBLY; + /* TODO: remove writeCode=&writeAssemblyCode; */ + + if (!checkAssemblyHeaderName(options[kOptAssembly].value)) { + fprintf(stderr, + "Assembly type \"%s\" is unknown.\n", options[kOptAssembly].value); + return -1; + } + } +#ifdef CAN_GENERATE_OBJECTS + else if(options[kOptObject].doesOccur) { + message="generating object code for %s\n"; + writeCode = CALL_WRITEOBJECT; + /* TODO: remove writeCode=&writeObjectCode; */ + } +#endif + else + { + message="generating C code for %s\n"; + writeCode = CALL_WRITECCODE; + /* TODO: remove writeCode=&writeCCode; */ + } + if (options[kOptQuiet].doesOccur) { + verbose = false; + } + while(--argc) { + filename=getLongPathname(argv[argc]); + if (verbose) { + fprintf(stdout, message, filename); + } + + switch (writeCode) { + case CALL_WRITECCODE: + writeCCode(filename, options[kOptDestDir].value, + options[kOptEntryPoint].doesOccur ? options[kOptEntryPoint].value : NULL, + options[kOptName].doesOccur ? options[kOptName].value : NULL, + options[kOptFilename].doesOccur ? options[kOptFilename].value : NULL, + NULL, + 0); + break; + case CALL_WRITEASSEMBLY: + writeAssemblyCode(filename, options[kOptDestDir].value, + options[kOptEntryPoint].doesOccur ? options[kOptEntryPoint].value : NULL, + options[kOptFilename].doesOccur ? options[kOptFilename].value : NULL, + NULL, + 0); + break; +#ifdef CAN_GENERATE_OBJECTS + case CALL_WRITEOBJECT: + if(options[kOptCpuArch].doesOccur) { + if (!checkCpuArchitecture(options[kOptCpuArch].value)) { + fprintf(stderr, + "CPU architecture \"%s\" is unknown.\n", options[kOptCpuArch].value); + return -1; + } + } + writeObjectCode(filename, options[kOptDestDir].value, + options[kOptEntryPoint].doesOccur ? options[kOptEntryPoint].value : NULL, + options[kOptMatchArch].doesOccur ? options[kOptMatchArch].value : NULL, + options[kOptCpuArch].doesOccur ? options[kOptCpuArch].value : NULL, + options[kOptFilename].doesOccur ? options[kOptFilename].value : NULL, + NULL, + 0, + !options[kOptSkipDllExport].doesOccur); + break; +#endif + default: + /* Should never occur. */ + break; + } + /* TODO: remove writeCode(filename, options[kOptDestDir].value); */ + } + } + + return 0; +} diff --git a/tools/icu/patches/75/source/tools/genccode/pkg_genc.h b/tools/icu/patches/75/source/tools/genccode/pkg_genc.h new file mode 100644 index 00000000000000..76474ec7df6fd8 --- /dev/null +++ b/tools/icu/patches/75/source/tools/genccode/pkg_genc.h @@ -0,0 +1,111 @@ +// © 2016 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html +/****************************************************************************** + * Copyright (C) 2008-2011, International Business Machines + * Corporation and others. All Rights Reserved. + ******************************************************************************* + */ + +#ifndef __PKG_GENC_H__ +#define __PKG_GENC_H__ + +#include "unicode/utypes.h" +#include "toolutil.h" + +#include "unicode/putil.h" +#include "putilimp.h" + +/*** Platform #defines move here ***/ +#if U_PLATFORM_HAS_WIN32_API +#ifdef __GNUC__ +#define WINDOWS_WITH_GNUC +#else +#define WINDOWS_WITH_MSVC +#endif +#endif + + +#if !defined(WINDOWS_WITH_MSVC) +#define BUILD_DATA_WITHOUT_ASSEMBLY +#endif + +#ifndef U_DISABLE_OBJ_CODE /* testing */ +#if defined(WINDOWS_WITH_MSVC) || U_PLATFORM_IS_LINUX_BASED +#define CAN_WRITE_OBJ_CODE +#endif +#if U_PLATFORM_HAS_WIN32_API || defined(U_ELF) +#define CAN_GENERATE_OBJECTS +#endif +#endif + +#if U_PLATFORM == U_PF_CYGWIN || defined(CYGWINMSVC) +#define USING_CYGWIN +#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 U_PLATFORM == U_PF_OS400 +#define USE_SINGLE_CCODE_FILE +#endif + +/* Need to fix the file seperator character when using MinGW. */ +#if defined(WINDOWS_WITH_GNUC) || defined(USING_CYGWIN) +#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 +#define SMALL_BUFFER_FLAG_NAMES 32 +#define BUFFER_PADDING_SIZE 20 + +/** End platform defines **/ + + + +U_CAPI void U_EXPORT2 +printAssemblyHeadersToStdErr(void); + +U_CAPI UBool U_EXPORT2 +checkAssemblyHeaderName(const char* optAssembly); + +U_CAPI UBool U_EXPORT2 +checkCpuArchitecture(const char* optCpuArch); + +U_CAPI void U_EXPORT2 +writeCCode( + const char *filename, + const char *destdir, + const char *optEntryPoint, + const char *optName, + const char *optFilename, + char *outFilePath, + size_t outFilePathCapacity); + +U_CAPI void U_EXPORT2 +writeAssemblyCode( + const char *filename, + const char *destdir, + const char *optEntryPoint, + const char *optFilename, + char *outFilePath, + size_t outFilePathCapacity); + +U_CAPI void U_EXPORT2 +writeObjectCode( + const char *filename, + const char *destdir, + const char *optEntryPoint, + const char *optMatchArch, + const char *optCpuArch, + const char *optFilename, + char *outFilePath, + size_t outFilePathCapacity, + UBool optWinDllExport); + +#endif diff --git a/tools/icu/patches/75/source/tools/pkgdata/pkgdata.cpp b/tools/icu/patches/75/source/tools/pkgdata/pkgdata.cpp new file mode 100644 index 00000000000000..51452a51bb3e48 --- /dev/null +++ b/tools/icu/patches/75/source/tools/pkgdata/pkgdata.cpp @@ -0,0 +1,2292 @@ +// © 2016 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html +/****************************************************************************** + * Copyright (C) 2000-2016, International Business Machines + * Corporation and others. All Rights Reserved. + ******************************************************************************* + * file name: pkgdata.cpp + * 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.) + */ + +// Defines _XOPEN_SOURCE for access to POSIX functions. +// Must be before any other #includes. +#include "uposixdefs.h" + +#include "unicode/utypes.h" + +#include "unicode/putil.h" +#include "putilimp.h" + +#if U_HAVE_POPEN +#if (U_PF_MINGW <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN) && defined(__STRICT_ANSI__) +/* popen/pclose aren't defined in strict ANSI on Cygwin and MinGW */ +#undef __STRICT_ANSI__ +#endif +#endif + +#include "cmemory.h" +#include "cstring.h" +#include "filestrm.h" +#include "toolutil.h" +#include "unicode/uclean.h" +#include "unewdata.h" +#include "uoptions.h" +#include "package.h" +#include "pkg_icu.h" +#include "pkg_genc.h" +#include "pkg_gencmn.h" +#include "flagparser.h" +#include "filetools.h" +#include "charstr.h" +#include "uassert.h" + +#if U_HAVE_POPEN +# include +#endif + +#include +#include + +U_CDECL_BEGIN +#include "pkgtypes.h" +U_CDECL_END + +#if U_HAVE_POPEN +U_NAMESPACE_BEGIN +U_DEFINE_LOCAL_OPEN_POINTER(LocalPipeFilePointer, FILE, pclose); +U_NAMESPACE_END +#endif + +using icu::LocalMemory; + +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, UBool specialHandling=false); +static int32_t pkg_installLibrary(const char *installDir, const char *dir, UBool noVersion); +static int32_t pkg_installFileMode(const char *installDir, const char *srcDir, const char *fileListName); +static int32_t pkg_installCommonMode(const char *installDir, const char *fileName); + +#ifdef BUILD_DATA_WITHOUT_ASSEMBLY +static int32_t pkg_createWithoutAssemblyCode(UPKGOptions *o, const char *targetDir, const char mode); +#endif + +#ifdef CAN_WRITE_OBJ_CODE +static void pkg_createOptMatchArch(char *optMatchArch); +static void pkg_destroyOptMatchArch(char *optMatchArch); +#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 = nullptr, UBool specialHandling=false); +static int32_t pkg_archiveLibrary(const char *targetDir, const char *version, UBool reverseExt); +static void createFileNames(UPKGOptions *o, const char mode, const char *version_major, const char *version, const char *libName, const UBool reverseExt, UBool noVersion); +static int32_t initializePkgDataFlags(UPKGOptions *o); + +static int32_t pkg_getPkgDataPath(UBool verbose, UOption *option); +static int runCommand(const char* command, UBool specialHandling=false); + +#define IN_COMMON_MODE(mode) (mode == 'a' || mode == 'c') +#define IN_DLL_MODE(mode) (mode == 'd' || mode == 'l') +#define IN_STATIC_MODE(mode) (mode == 's') +#define IN_FILES_MODE(mode) (mode == 'f') + +enum { + NAME, + BLDOPT, + MODE, + HELP, + HELP_QUESTION_MARK, + VERBOSE, + COPYRIGHT, + COMMENT, + DESTDIR, + REBUILD, + TEMPDIR, + INSTALL, + SOURCEDIR, + ENTRYPOINT, + REVISION, + FORCE_PREFIX, + LIBNAME, + QUIET, + WITHOUT_ASSEMBLY, + PDS_BUILD, + WIN_UWP_BUILD, + WIN_DLL_ARCH, + WIN_DYNAMICBASE +}; + +/* This sets the modes that are available */ +static struct { + const char *name, *alt_name; + const char *desc; +} modes[] = { + { "files", nullptr, "Uses raw data files (no effect). Installation copies all files to the target location." }, +#if U_PLATFORM_HAS_WIN32_API + { "dll", "library", "Generates one common data file and one shared library, .dll"}, + { "common", "archive", "Generates just the common file, .dat"}, + { "static", "static", "Generates one statically linked library, " LIB_PREFIX "" UDATA_LIB_SUFFIX } +#else +#ifdef UDATA_SO_SUFFIX + { "dll", "library", "Generates one shared library, " UDATA_SO_SUFFIX }, +#endif + { "common", "archive", "Generates one common data file, .dat" }, + { "static", "static", "Generates one statically linked library, " LIB_PREFIX "" 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), + /*20*/ UOPTION_DEF( "without-assembly", 'w', UOPT_NO_ARG), + /*21*/ UOPTION_DEF("zos-pds-build", 'z', UOPT_NO_ARG), + /*22*/ UOPTION_DEF("windows-uwp-build", 'u', UOPT_NO_ARG), + /*23*/ UOPTION_DEF("windows-DLL-arch", 'a', UOPT_REQUIRES_ARG), + /*24*/ UOPTION_DEF("windows-dynamicbase", 'b', UOPT_NO_ARG), +}; + +/* This enum and the following char array should be kept in sync. */ +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 const char* FLAG_NAMES[PKGDATA_FLAGS_SIZE] = { + "GENCCODE_ASSEMBLY_TYPE", + "SO", + "SOBJ", + "A", + "LIBPREFIX", + "LIB_EXT_ORDER", + "COMPILE", + "LIBFLAGS", + "GENLIB", + "LDICUDTFLAGS", + "LD_SONAME", + "RPATH_FLAGS", + "BIR_LDFLAGS", + "AR", + "ARFLAGS", + "RANLIB", + "INSTALL_CMD" +}; +static char **pkgDataFlags = nullptr; + +enum { + LIB_FILE, + LIB_FILE_VERSION_MAJOR, + LIB_FILE_VERSION, + LIB_FILE_VERSION_TMP, +#if U_PLATFORM == U_PF_CYGWIN + LIB_FILE_CYGWIN, + LIB_FILE_CYGWIN_VERSION, +#elif U_PLATFORM == U_PF_MINGW + LIB_FILE_MINGW, +#elif U_PLATFORM == U_PF_OS390 + LIB_FILE_OS390BATCH_MAJOR, + LIB_FILE_OS390BATCH_VERSION, +#endif + LIB_FILENAMES_SIZE +}; +static char libFileNames[LIB_FILENAMES_SIZE][256]; + +static UPKGOptions *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. 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)", + "Quiet mode. (e.g. Do not output a readme file for static libraries)", + "Build the data without assembly code", + "Build PDS dataset (zOS build only)", + "Build for Universal Windows Platform (Windows build only)", + "Specify the DLL machine architecture for LINK.exe (Windows build only)", + "Ignored. Enable DYNAMICBASE on the DLL. This is now the default. (Windows build only)", +}; + +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, UPRV_LENGTHOF(options), 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; + } + + +#if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN) + if(!options[BLDOPT].doesOccur && uprv_strcmp(options[MODE].value, "common") != 0) { + if (pkg_getPkgDataPath(options[VERBOSE].doesOccur, &options[BLDOPT]) != 0) { + fprintf(stderr, " required parameter is missing: -O is required for static and shared builds.\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(strlen(command)); + + if (len == 0) { + return 0; + } + + if (!specialHandling) { +#if defined(USING_CYGWIN) || U_PLATFORM == U_PF_MINGW || U_PLATFORM == U_PF_OS400 + int32_t buff_len; + if ((len + BUFFER_PADDING_SIZE) >= SMALL_BUFFER_MAX_SIZE) { + cmd = (char *)uprv_malloc(len + BUFFER_PADDING_SIZE); + buff_len = len + BUFFER_PADDING_SIZE; + } else { + cmd = cmdBuffer; + buff_len = SMALL_BUFFER_MAX_SIZE; + } +#if defined(USING_CYGWIN) || U_PLATFORM == U_PF_MINGW + snprintf(cmd, buff_len, "bash -c \"%s\"", command); + +#elif U_PLATFORM == U_PF_OS400 + snprintf(cmd, buff_len "QSH CMD('%s')", command); +#endif +#else + goto normal_command_mode; +#endif + } else { +#if !(defined(USING_CYGWIN) || U_PLATFORM == U_PF_MINGW || U_PLATFORM == U_PF_OS400) +normal_command_mode: +#endif + cmd = (char *)command; + } + + printf("pkgdata: %s\n", cmd); + int result = system(cmd); + if (result != 0) { + fprintf(stderr, "-- return status = %d\n", result); + result = 1; // system() result code is platform specific. + } + + if (cmd != cmdBuffer && cmd != command) { + uprv_free(cmd); + } + + return result; +} + +#define LN_CMD "ln -s" +#define RM_CMD "rm -f" + +static int32_t pkg_executeOptions(UPKGOptions *o) { + int32_t result = 0; + + 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] = ""; + + initializePkgDataFlags(o); + + if (IN_FILES_MODE(mode)) { + /* Copy the raw data to the installation directory. */ + if (o->install != nullptr) { + uprv_strcpy(targetDir, o->install); + if (o->shortName != nullptr) { + uprv_strcat(targetDir, PKGDATA_FILE_SEP_STRING); + uprv_strcat(targetDir, o->shortName); + } + + if(o->verbose) { + fprintf(stdout, "# Install: Files mode, copying files to %s..\n", targetDir); + } + result = pkg_installFileMode(targetDir, o->srcDir, o->fileListFiles->str); + } + return result; + } else /* if (IN_COMMON_MODE(mode) || IN_DLL_MODE(mode) || IN_STATIC_MODE(mode)) */ { + UBool noVersion = false; + + 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); + + if(o->verbose) { + fprintf(stdout, "# Writing package file %s ..\n", datFileNamePath); + } + result = writePackageDatFile(datFileNamePath, o->comment, o->srcDir, o->fileListFiles->str, nullptr, U_CHARSET_FAMILY ? 'e' : U_IS_BIG_ENDIAN ? 'b' : 'l'); + if (result != 0) { + fprintf(stderr,"Error writing package dat file.\n"); + return result; + } + + if (IN_COMMON_MODE(mode)) { + char targetFileNamePath[LARGE_BUFFER_MAX_SIZE] = ""; + + uprv_strcpy(targetFileNamePath, targetDir); + uprv_strcat(targetFileNamePath, datFileName); + + /* Move the dat file created to the target directory. */ + if (uprv_strcmp(datFileNamePath, targetFileNamePath) != 0) { + if (T_FileStream_file_exists(targetFileNamePath)) { + if ((result = remove(targetFileNamePath)) != 0) { + fprintf(stderr, "Unable to remove old dat file: %s\n", + targetFileNamePath); + return result; + } + } + + result = rename(datFileNamePath, targetFileNamePath); + + if (o->verbose) { + fprintf(stdout, "# Moving package file to %s ..\n", + targetFileNamePath); + } + if (result != 0) { + fprintf( + stderr, + "Unable to move dat file (%s) to target location (%s).\n", + datFileNamePath, targetFileNamePath); + return result; + } + } + + if (o->install != nullptr) { + result = pkg_installCommonMode(o->install, targetFileNamePath); + } + + return result; + } else /* if (IN_STATIC_MODE(mode) || IN_DLL_MODE(mode)) */ { + char gencFilePath[SMALL_BUFFER_MAX_SIZE] = ""; + char version_major[10] = ""; + UBool reverseExt = false; + +#if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN) + /* Get the version major number. */ + if (o->version != nullptr) { + 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]; + } + } else { + noVersion = true; + if (IN_DLL_MODE(mode)) { + fprintf(stdout, "Warning: Providing a revision number with the -r option is recommended when packaging data in the current mode.\n"); + } + } + +#if U_PLATFORM != U_PF_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(o, mode, version_major, o->version == nullptr ? "" : o->version, o->libName, reverseExt, noVersion); + + if ((o->version!=nullptr || IN_STATIC_MODE(mode)) && o->rebuild == false && o->pdsbuild == false) { + /* Check to see if a previous built data library file exists and check if it is the latest. */ + snprintf(checkLibFile, sizeof(checkLibFile), "%s%s", targetDir, libFileNames[LIB_FILE_VERSION]); + if (T_FileStream_file_exists(checkLibFile)) { + if (isFileModTimeLater(checkLibFile, o->srcDir, true) && isFileModTimeLater(checkLibFile, o->options)) { + if (o->install != nullptr) { + if(o->verbose) { + fprintf(stdout, "# Installing already-built library into %s\n", o->install); + } + result = pkg_installLibrary(o->install, targetDir, noVersion); + } else { + if(o->verbose) { + printf("# Not rebuilding %s - up to date.\n", checkLibFile); + } + } + return result; + } else if (o->verbose && (o->install!=nullptr)) { + fprintf(stdout, "# Not installing up-to-date library %s into %s\n", checkLibFile, o->install); + } + } else if(o->verbose && (o->install!=nullptr)) { + fprintf(stdout, "# Not installing missing %s into %s\n", checkLibFile, o->install); + } + } + + if (pkg_checkFlag(o) == nullptr) { + /* Error occurred. */ + return result; + } +#endif + + if (!o->withoutAssembly && pkgDataFlags[GENCCODE_ASSEMBLY_TYPE][0] != 0) { + const char* genccodeAssembly = pkgDataFlags[GENCCODE_ASSEMBLY_TYPE]; + + if(o->verbose) { + fprintf(stdout, "# Generating assembly code %s of type %s ..\n", gencFilePath, genccodeAssembly); + } + + /* Offset genccodeAssembly by 3 because "-a " */ + if (genccodeAssembly && + (uprv_strlen(genccodeAssembly)>3) && + checkAssemblyHeaderName(genccodeAssembly+3)) { + writeAssemblyCode( + datFileNamePath, + o->tmpDir, + o->entryName, + nullptr, + gencFilePath, + sizeof(gencFilePath)); + + result = pkg_createWithAssemblyCode(targetDir, mode, gencFilePath); + if (result != 0) { + fprintf(stderr, "Error generating assembly code for data.\n"); + return result; + } else if (IN_STATIC_MODE(mode)) { + if(o->install != nullptr) { + if(o->verbose) { + fprintf(stdout, "# Installing static library into %s\n", o->install); + } + result = pkg_installLibrary(o->install, targetDir, noVersion); + } + return result; + } + } else { + fprintf(stderr,"Assembly type \"%s\" is unknown.\n", genccodeAssembly); + return -1; + } + } else { + if(o->verbose) { + fprintf(stdout, "# Writing object code to %s ..\n", gencFilePath); + } + if (o->withoutAssembly) { +#ifdef BUILD_DATA_WITHOUT_ASSEMBLY + result = pkg_createWithoutAssemblyCode(o, targetDir, mode); +#else + /* This error should not occur. */ + fprintf(stderr, "Error- BUILD_DATA_WITHOUT_ASSEMBLY is not defined. Internal error.\n"); +#endif + } else { +#ifdef CAN_WRITE_OBJ_CODE + /* Try to detect the arch type, use nullptr if unsuccessful */ + char optMatchArch[10] = { 0 }; + pkg_createOptMatchArch(optMatchArch); + writeObjectCode( + datFileNamePath, + o->tmpDir, + o->entryName, + (optMatchArch[0] == 0 ? nullptr : optMatchArch), + nullptr, + nullptr, + gencFilePath, + sizeof(gencFilePath), + true); + pkg_destroyOptMatchArch(optMatchArch); +#if U_PLATFORM_IS_LINUX_BASED + result = pkg_generateLibraryFile(targetDir, mode, gencFilePath); +#elif defined(WINDOWS_WITH_MSVC) + result = pkg_createWindowsDLL(mode, gencFilePath, o); +#endif +#elif defined(BUILD_DATA_WITHOUT_ASSEMBLY) + result = pkg_createWithoutAssemblyCode(o, targetDir, mode); +#else + fprintf(stderr, "Error- neither CAN_WRITE_OBJ_CODE nor BUILD_DATA_WITHOUT_ASSEMBLY are defined. Internal error.\n"); + return 1; +#endif + } + + if (result != 0) { + fprintf(stderr, "Error generating package data.\n"); + return result; + } + } +#if !U_PLATFORM_USES_ONLY_WIN32_API + if(!IN_STATIC_MODE(mode)) { + /* Certain platforms uses archive library. (e.g. AIX) */ + if(o->verbose) { + fprintf(stdout, "# Creating data archive library file ..\n"); + } + result = pkg_archiveLibrary(targetDir, o->version, reverseExt); + if (result != 0) { + fprintf(stderr, "Error creating data archive library file.\n"); + return result; + } +#if U_PLATFORM != U_PF_OS400 + if (!noVersion) { + /* Create symbolic links for the final library file. */ +#if U_PLATFORM == U_PF_OS390 + result = pkg_createSymLinks(targetDir, o->pdsbuild); +#else + result = pkg_createSymLinks(targetDir, noVersion); +#endif + if (result != 0) { + fprintf(stderr, "Error creating symbolic links of the data library file.\n"); + return result; + } + } +#endif + } /* !IN_STATIC_MODE */ +#endif + +#if !U_PLATFORM_USES_ONLY_WIN32_API + /* Install the libraries if option was set. */ + if (o->install != nullptr) { + if(o->verbose) { + fprintf(stdout, "# Installing library file to %s ..\n", o->install); + } + result = pkg_installLibrary(o->install, targetDir, noVersion); + if (result != 0) { + fprintf(stderr, "Error installing the data library.\n"); + return result; + } + } +#endif + } + } + return result; +} + +/* Initialize the pkgDataFlags with the option file given. */ +static int32_t initializePkgDataFlags(UPKGOptions *o) { + UErrorCode status = U_ZERO_ERROR; + int32_t result = 0; + int32_t currentBufferSize = SMALL_BUFFER_MAX_SIZE; + int32_t tmpResult = 0; + + /* Initialize pkgdataFlags */ + pkgDataFlags = (char**)uprv_malloc(sizeof(char*) * PKGDATA_FLAGS_SIZE); + + /* If we run out of space, allocate more */ +#if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN) + do { +#endif + if (pkgDataFlags != nullptr) { + for (int32_t i = 0; i < PKGDATA_FLAGS_SIZE; i++) { + pkgDataFlags[i] = (char*)uprv_malloc(sizeof(char) * currentBufferSize); + if (pkgDataFlags[i] != nullptr) { + pkgDataFlags[i][0] = 0; + } else { + fprintf(stderr,"Error allocating memory for pkgDataFlags.\n"); + /* If an error occurs, ensure that the rest of the array is nullptr */ + for (int32_t n = i + 1; n < PKGDATA_FLAGS_SIZE; n++) { + pkgDataFlags[n] = nullptr; + } + return -1; + } + } + } else { + fprintf(stderr,"Error allocating memory for pkgDataFlags.\n"); + return -1; + } + + if (o->options == nullptr) { + return result; + } + +#if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN) + /* Read in options file. */ + if(o->verbose) { + fprintf(stdout, "# Reading options file %s\n", o->options); + } + status = U_ZERO_ERROR; + tmpResult = parseFlagsFile(o->options, pkgDataFlags, currentBufferSize, FLAG_NAMES, (int32_t)PKGDATA_FLAGS_SIZE, &status); + if (status == U_BUFFER_OVERFLOW_ERROR) { + for (int32_t i = 0; i < PKGDATA_FLAGS_SIZE; i++) { + if (pkgDataFlags[i]) { + uprv_free(pkgDataFlags[i]); + pkgDataFlags[i] = nullptr; + } + } + currentBufferSize = tmpResult; + } else if (U_FAILURE(status)) { + fprintf(stderr,"Unable to open or read \"%s\" option file. status = %s\n", o->options, u_errorName(status)); + return -1; + } +#endif + if(o->verbose) { + fprintf(stdout, "# pkgDataFlags=\n"); + for(int32_t i=0;iverbose) { + fprintf(stdout, "# libFileName[LIB_FILE] = %s\n", libFileNames[LIB_FILE]); + } + +#if U_PLATFORM == U_PF_MINGW + // Name the import library lib*.dll.a + snprintf(libFileNames[LIB_FILE_MINGW], sizeof(libFileNames[LIB_FILE_MINGW]), "lib%s.dll.a", libName); +#elif U_PLATFORM == U_PF_CYGWIN + snprintf(libFileNames[LIB_FILE_CYGWIN], sizeof(libFileNames[LIB_FILE_CYGWIN]), "cyg%s%s%s", + libName, + FILE_EXTENSION_SEP, + pkgDataFlags[SO_EXT]); + snprintf(libFileNames[LIB_FILE_CYGWIN_VERSION], sizeof(libFileNames[LIB_FILE_CYGWIN_VERSION]), "cyg%s%s%s%s", + libName, + version_major, + FILE_EXTENSION_SEP, + pkgDataFlags[SO_EXT]); + + uprv_strcat(pkgDataFlags[SO_EXT], "."); + uprv_strcat(pkgDataFlags[SO_EXT], pkgDataFlags[A_EXT]); +#elif U_PLATFORM == U_PF_OS400 || defined(_AIX) + snprintf(libFileNames[LIB_FILE_VERSION_TMP], sizeof(libFileNames[LIB_FILE_VERSION_TMP]), "%s%s%s", + libFileNames[LIB_FILE], + FILE_EXTENSION_SEP, + pkgDataFlags[SOBJ_EXT]); +#elif U_PLATFORM == U_PF_OS390 + snprintf(libFileNames[LIB_FILE_VERSION_TMP], sizeof(libFileNames[LIB_FILE_VERSION_TMP]), "%s%s%s%s%s", + libFileNames[LIB_FILE], + pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "", + reverseExt ? version : pkgDataFlags[SOBJ_EXT], + FILE_EXTENSION_SEP, + reverseExt ? pkgDataFlags[SOBJ_EXT] : version); + + snprintf(libFileNames[LIB_FILE_OS390BATCH_VERSION], sizeof(libFileNames[LIB_FILE_OS390BATCH_VERSION]), "%s%s.x", + libFileNames[LIB_FILE], + version); + snprintf(libFileNames[LIB_FILE_OS390BATCH_MAJOR], sizeof(libFileNames[LIB_FILE_OS390BATCH_MAJOR]), "%s%s.x", + libFileNames[LIB_FILE], + version_major); +#else + if (noVersion && !reverseExt) { + snprintf(libFileNames[LIB_FILE_VERSION_TMP], sizeof(libFileNames[LIB_FILE_VERSION_TMP]), "%s%s%s", + libFileNames[LIB_FILE], + FILE_SUFFIX, + pkgDataFlags[SOBJ_EXT]); + } else { + snprintf(libFileNames[LIB_FILE_VERSION_TMP], sizeof(libFileNames[LIB_FILE_VERSION_TMP]), "%s%s%s%s%s", + libFileNames[LIB_FILE], + FILE_SUFFIX, + reverseExt ? version : pkgDataFlags[SOBJ_EXT], + FILE_EXTENSION_SEP, + reverseExt ? pkgDataFlags[SOBJ_EXT] : version); + } +#endif + if (noVersion && !reverseExt) { + snprintf(libFileNames[LIB_FILE_VERSION_MAJOR], sizeof(libFileNames[LIB_FILE_VERSION_TMP]), "%s%s%s", + libFileNames[LIB_FILE], + FILE_SUFFIX, + pkgDataFlags[SO_EXT]); + + snprintf(libFileNames[LIB_FILE_VERSION], sizeof(libFileNames[LIB_FILE_VERSION]), "%s%s%s", + libFileNames[LIB_FILE], + FILE_SUFFIX, + pkgDataFlags[SO_EXT]); + } else { + snprintf(libFileNames[LIB_FILE_VERSION_MAJOR], sizeof(libFileNames[LIB_FILE_VERSION_MAJOR]), "%s%s%s%s%s", + libFileNames[LIB_FILE], + FILE_SUFFIX, + reverseExt ? version_major : pkgDataFlags[SO_EXT], + FILE_EXTENSION_SEP, + reverseExt ? pkgDataFlags[SO_EXT] : version_major); + + snprintf(libFileNames[LIB_FILE_VERSION], sizeof(libFileNames[LIB_FILE_VERSION]), "%s%s%s%s%s", + libFileNames[LIB_FILE], + FILE_SUFFIX, + reverseExt ? version : pkgDataFlags[SO_EXT], + FILE_EXTENSION_SEP, + reverseExt ? pkgDataFlags[SO_EXT] : version); + } + + if(o->verbose) { + fprintf(stdout, "# libFileName[LIB_FILE_VERSION] = %s\n", libFileNames[LIB_FILE_VERSION]); + } + +#if U_PF_MINGW <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN + /* Cygwin and MinGW only deals with the version major number. */ + uprv_strcpy(libFileNames[LIB_FILE_VERSION_TMP], libFileNames[LIB_FILE_VERSION_MAJOR]); +#endif + + if(IN_STATIC_MODE(mode)) { + snprintf(libFileNames[LIB_FILE_VERSION], sizeof(libFileNames[LIB_FILE_VERSION]), "%s.%s", libFileNames[LIB_FILE], pkgDataFlags[A_EXT]); + libFileNames[LIB_FILE_VERSION_MAJOR][0]=0; + if(o->verbose) { + fprintf(stdout, "# libFileName[LIB_FILE_VERSION] = %s (static)\n", libFileNames[LIB_FILE_VERSION]); + } + } +} + +/* Create the symbolic links for the final library file. */ +static int32_t pkg_createSymLinks(const char *targetDir, UBool specialHandling) { + int32_t result = 0; + char cmd[LARGE_BUFFER_MAX_SIZE]; + char name1[SMALL_BUFFER_MAX_SIZE]; /* symlink file name */ + char name2[SMALL_BUFFER_MAX_SIZE]; /* file name to symlink */ + const char* FILE_EXTENSION_SEP = uprv_strlen(pkgDataFlags[SO_EXT]) == 0 ? "" : "."; + +#if U_PLATFORM != U_PF_CYGWIN + /* No symbolic link to make. */ + if (uprv_strlen(libFileNames[LIB_FILE_VERSION]) == 0 || uprv_strlen(libFileNames[LIB_FILE_VERSION_MAJOR]) == 0 || + uprv_strcmp(libFileNames[LIB_FILE_VERSION], libFileNames[LIB_FILE_VERSION_MAJOR]) == 0) { + return result; + } + + snprintf(cmd, sizeof(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 = runCommand(cmd); + if (result != 0) { + fprintf(stderr, "Error creating symbolic links. Failed command: %s\n", cmd); + return result; + } +#endif + + if (specialHandling) { +#if U_PLATFORM == U_PF_CYGWIN + snprintf(name1, sizeof(name1), "%s", libFileNames[LIB_FILE_CYGWIN]); + snprintf(name2, sizeof(name2), "%s", libFileNames[LIB_FILE_CYGWIN_VERSION]); +#elif U_PLATFORM == U_PF_OS390 + /* Create the symbolic links for the import data */ + /* Use the cmd buffer to store path to import data file to check its existence */ + snprintf(cmd, sizeof(cmd), "%s/%s", targetDir, libFileNames[LIB_FILE_OS390BATCH_VERSION]); + if (T_FileStream_file_exists(cmd)) { + snprintf(cmd, sizeof(cmd), "cd %s && %s %s && %s %s %s", + targetDir, + RM_CMD, + libFileNames[LIB_FILE_OS390BATCH_MAJOR], + LN_CMD, + libFileNames[LIB_FILE_OS390BATCH_VERSION], + libFileNames[LIB_FILE_OS390BATCH_MAJOR]); + result = runCommand(cmd); + if (result != 0) { + fprintf(stderr, "Error creating symbolic links. Failed command: %s\n", cmd); + return result; + } + + snprintf(cmd, sizeof(cmd), "cd %s && %s %s.x && %s %s %s.x", + targetDir, + RM_CMD, + libFileNames[LIB_FILE], + LN_CMD, + libFileNames[LIB_FILE_OS390BATCH_VERSION], + libFileNames[LIB_FILE]); + result = runCommand(cmd); + if (result != 0) { + fprintf(stderr, "Error creating symbolic links. Failed command: %s\n", cmd); + return result; + } + } + + /* Needs to be set here because special handling skips it */ + snprintf(name1, sizeof(name1), "%s%s%s", libFileNames[LIB_FILE], FILE_EXTENSION_SEP, pkgDataFlags[SO_EXT]); + snprintf(name2, sizeof(name2), "%s", libFileNames[LIB_FILE_VERSION]); +#else + goto normal_symlink_mode; +#endif + } else { +#if U_PLATFORM != U_PF_CYGWIN +normal_symlink_mode: +#endif + snprintf(name1, sizeof(name1), "%s%s%s", libFileNames[LIB_FILE], FILE_EXTENSION_SEP, pkgDataFlags[SO_EXT]); + snprintf(name2, sizeof(name2), "%s", libFileNames[LIB_FILE_VERSION]); + } + + snprintf(cmd, sizeof(cmd), "cd %s && %s %s && %s %s %s", + targetDir, + RM_CMD, + name1, + LN_CMD, + name2, + name1); + + result = runCommand(cmd); + + return result; +} + +static int32_t pkg_installLibrary(const char *installDir, const char *targetDir, UBool noVersion) { + int32_t result = 0; + char cmd[SMALL_BUFFER_MAX_SIZE]; + + auto ret = snprintf(cmd, + sizeof(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]); + (void)ret; + U_ASSERT(0 <= ret && ret < SMALL_BUFFER_MAX_SIZE); + + result = runCommand(cmd); + + if (result != 0) { + fprintf(stderr, "Error installing library. Failed command: %s\n", cmd); + return result; + } + +#ifdef CYGWINMSVC + snprintf(cmd, sizeof(cmd), "cd %s && %s %s.lib %s", + targetDir, + pkgDataFlags[INSTALL_CMD], + libFileNames[LIB_FILE], + installDir + ); + result = runCommand(cmd); + + if (result != 0) { + fprintf(stderr, "Error installing library. Failed command: %s\n", cmd); + return result; + } +#elif U_PLATFORM == U_PF_CYGWIN + snprintf(cmd, sizeof(cmd), "cd %s && %s %s %s", + targetDir, + pkgDataFlags[INSTALL_CMD], + libFileNames[LIB_FILE_CYGWIN_VERSION], + installDir + ); + result = runCommand(cmd); + + if (result != 0) { + fprintf(stderr, "Error installing library. Failed command: %s\n", cmd); + return result; + } + +#elif U_PLATFORM == U_PF_OS390 + if (T_FileStream_file_exists(libFileNames[LIB_FILE_OS390BATCH_VERSION])) { + snprintf(cmd, sizeof(cmd), "%s %s %s", + pkgDataFlags[INSTALL_CMD], + libFileNames[LIB_FILE_OS390BATCH_VERSION], + installDir + ); + result = runCommand(cmd); + + if (result != 0) { + fprintf(stderr, "Error installing library. Failed command: %s\n", cmd); + return result; + } + } +#endif + + if (noVersion) { + return result; + } else { + return pkg_createSymLinks(installDir, true); + } +} + +static int32_t pkg_installCommonMode(const char *installDir, const char *fileName) { + 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 + snprintf(cmd, sizeof(cmd), "%s %s %s", pkgDataFlags[INSTALL_CMD], fileName, installDir); +#else + snprintf(cmd, sizeof(cmd), "%s %s %s %s", WIN_INSTALL_CMD, fileName, installDir, WIN_INSTALL_CMD_FLAGS); +#endif + + result = runCommand(cmd); + if (result != 0) { + fprintf(stderr, "Failed to install data file with command: %s\n", cmd); + } + + return result; +} + +#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] = ""; + int32_t bufferLength = 0; + + FileStream *f = T_FileStream_open(fileListName, "r"); + if (f != nullptr) { + for(;;) { + if (T_FileStream_readLine(f, buffer, SMALL_BUFFER_MAX_SIZE) != nullptr) { + bufferLength = static_cast(uprv_strlen(buffer)); + /* Remove new line character. */ + if (bufferLength > 0) { + buffer[bufferLength-1] = 0; + } + + auto ret = snprintf(cmd, + sizeof(cmd), + "%s %s%s%s %s%s%s", + pkgDataFlags[INSTALL_CMD], + srcDir, PKGDATA_FILE_SEP_STRING, buffer, + installDir, PKGDATA_FILE_SEP_STRING, buffer); + (void)ret; + U_ASSERT(0 <= ret && ret < SMALL_BUFFER_MAX_SIZE); + + result = runCommand(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 + snprintf(cmd, sizeof(cmd), "%s %s %s %s", WIN_INSTALL_CMD, srcDir, installDir, WIN_INSTALL_CMD_FLAGS); + result = runCommand(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 shared 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) { + snprintf(libFileNames[LIB_FILE_VERSION], sizeof(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); + + snprintf(cmd, sizeof(cmd), "%s %s %s%s %s%s", + pkgDataFlags[AR], + pkgDataFlags[ARFLAGS], + targetDir, + libFileNames[LIB_FILE_VERSION], + targetDir, + libFileNames[LIB_FILE_VERSION_TMP]); + + result = runCommand(cmd); + if (result != 0) { + fprintf(stderr, "Error creating archive library. Failed command: %s\n", cmd); + return result; + } + + snprintf(cmd, sizeof(cmd), "%s %s%s", + pkgDataFlags[RANLIB], + targetDir, + libFileNames[LIB_FILE_VERSION]); + + result = runCommand(cmd); + if (result != 0) { + fprintf(stderr, "Error creating archive library. Failed command: %s\n", cmd); + return result; + } + + /* Remove unneeded library file. */ + snprintf(cmd, sizeof(cmd), "%s %s%s", + RM_CMD, + targetDir, + libFileNames[LIB_FILE_VERSION_TMP]); + + result = runCommand(cmd); + if (result != 0) { + fprintf(stderr, "Error creating archive library. Failed command: %s\n", cmd); + 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, UBool specialHandling) { + int32_t result = 0; + char *cmd = nullptr; + UBool freeCmd = false; + int32_t length = 0; + + (void)specialHandling; // Suppress unused variable compiler warnings on platforms where all usage + // of this parameter is #ifdefed out. + + /* 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 != nullptr) { + cmd = command; + } + + if (IN_STATIC_MODE(mode)) { + if (cmd == nullptr) { + length = static_cast(uprv_strlen(pkgDataFlags[AR]) + uprv_strlen(pkgDataFlags[ARFLAGS]) + uprv_strlen(targetDir) + + uprv_strlen(libFileNames[LIB_FILE_VERSION]) + uprv_strlen(objectFile) + uprv_strlen(pkgDataFlags[RANLIB]) + BUFFER_PADDING_SIZE); + if ((cmd = (char *)uprv_malloc(sizeof(char) * length)) == nullptr) { + fprintf(stderr, "Unable to allocate memory for command.\n"); + return -1; + } + freeCmd = true; + } + sprintf(cmd, "%s %s %s%s %s", + pkgDataFlags[AR], + pkgDataFlags[ARFLAGS], + targetDir, + libFileNames[LIB_FILE_VERSION], + objectFile); + + result = runCommand(cmd); + if (result == 0) { + sprintf(cmd, "%s %s%s", + pkgDataFlags[RANLIB], + targetDir, + libFileNames[LIB_FILE_VERSION]); + + result = runCommand(cmd); + } + } else /* if (IN_DLL_MODE(mode)) */ { + if (cmd == nullptr) { + length = static_cast(uprv_strlen(pkgDataFlags[GENLIB]) + uprv_strlen(pkgDataFlags[LDICUDTFLAGS]) + + ((uprv_strlen(targetDir) + uprv_strlen(libFileNames[LIB_FILE_VERSION_TMP])) * 2) + + uprv_strlen(objectFile) + uprv_strlen(pkgDataFlags[LD_SONAME]) + + uprv_strlen(pkgDataFlags[LD_SONAME][0] == 0 ? "" : libFileNames[LIB_FILE_VERSION_MAJOR]) + + uprv_strlen(pkgDataFlags[RPATH_FLAGS]) + uprv_strlen(pkgDataFlags[BIR_FLAGS]) + BUFFER_PADDING_SIZE); +#if U_PLATFORM == U_PF_CYGWIN + length += static_cast(uprv_strlen(targetDir) + uprv_strlen(libFileNames[LIB_FILE_CYGWIN_VERSION])); +#elif U_PLATFORM == U_PF_MINGW + length += static_cast(uprv_strlen(targetDir) + uprv_strlen(libFileNames[LIB_FILE_MINGW])); +#endif + if ((cmd = (char *)uprv_malloc(sizeof(char) * length)) == nullptr) { + fprintf(stderr, "Unable to allocate memory for command.\n"); + return -1; + } + freeCmd = true; + } +#if U_PLATFORM == U_PF_MINGW + sprintf(cmd, "%s%s%s %s -o %s%s %s %s%s %s %s", + pkgDataFlags[GENLIB], + targetDir, + libFileNames[LIB_FILE_MINGW], + pkgDataFlags[LDICUDTFLAGS], + targetDir, + libFileNames[LIB_FILE_VERSION_TMP], +#elif U_PLATFORM == U_PF_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_VERSION], +#elif U_PLATFORM == U_PF_AIX + sprintf(cmd, "%s %s%s;%s %s -o %s%s %s %s%s %s %s", + RM_CMD, + targetDir, + libFileNames[LIB_FILE_VERSION_TMP], + pkgDataFlags[GENLIB], + pkgDataFlags[LDICUDTFLAGS], + targetDir, + libFileNames[LIB_FILE_VERSION_TMP], +#else + sprintf(cmd, "%s %s -o %s%s %s %s%s %s %s", + 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 = runCommand(cmd); + +#if U_PLATFORM == U_PF_OS390 + char *env_tmp; + char PDS_LibName[512]; + char PDS_Name[512]; + + PDS_Name[0] = 0; + PDS_LibName[0] = 0; + if (specialHandling && uprv_strcmp(libFileNames[LIB_FILE],"libicudata") == 0) { + if (env_tmp = getenv("ICU_PDS_NAME")) { + sprintf(PDS_Name, "%s%s", + env_tmp, + "DA"); + strcat(PDS_Name, getenv("ICU_PDS_NAME_SUFFIX")); + } else if (env_tmp = getenv("PDS_NAME_PREFIX")) { + sprintf(PDS_Name, "%s%s", + env_tmp, + U_ICU_VERSION_SHORT "DA"); + } else { + sprintf(PDS_Name, "%s%s", + "IXMI", + U_ICU_VERSION_SHORT "DA"); + } + } else if (!specialHandling && uprv_strcmp(libFileNames[LIB_FILE],"libicudata_stub") == 0) { + if (env_tmp = getenv("ICU_PDS_NAME")) { + sprintf(PDS_Name, "%s%s", + env_tmp, + "D1"); + strcat(PDS_Name, getenv("ICU_PDS_NAME_SUFFIX")); + } else if (env_tmp = getenv("PDS_NAME_PREFIX")) { + sprintf(PDS_Name, "%s%s", + env_tmp, + U_ICU_VERSION_SHORT "D1"); + } else { + sprintf(PDS_Name, "%s%s", + "IXMI", + U_ICU_VERSION_SHORT "D1"); + } + } + + if (PDS_Name[0]) { + sprintf(PDS_LibName,"%s%s%s%s%s", + "\"//'", + getenv("LOADMOD"), + "(", + PDS_Name, + ")'\""); + sprintf(cmd, "%s %s -o %s %s %s%s %s %s", + pkgDataFlags[GENLIB], + pkgDataFlags[LDICUDTFLAGS], + PDS_LibName, + objectFile, + pkgDataFlags[LD_SONAME], + pkgDataFlags[LD_SONAME][0] == 0 ? "" : libFileNames[LIB_FILE_VERSION_MAJOR], + pkgDataFlags[RPATH_FLAGS], + pkgDataFlags[BIR_FLAGS]); + + result = runCommand(cmd); + } +#endif + } + + if (result != 0) { + fprintf(stderr, "Error generating library file. Failed command: %s\n", 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] = ""; + int32_t result = 0; + int32_t length = 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'; + + length = static_cast(uprv_strlen(pkgDataFlags[COMPILER]) + uprv_strlen(pkgDataFlags[LIBFLAGS]) + + uprv_strlen(tempObjectFile) + uprv_strlen(gencFilePath) + BUFFER_PADDING_SIZE); + + LocalMemory cmd((char *)uprv_malloc(sizeof(char) * length)); + if (cmd.isNull()) { + return -1; + } + + /* Generate the object file. */ + snprintf(cmd.getAlias(), length, "%s %s -o %s %s", + pkgDataFlags[COMPILER], + pkgDataFlags[LIBFLAGS], + tempObjectFile, + gencFilePath); + + result = runCommand(cmd.getAlias()); + + if (result != 0) { + fprintf(stderr, "Error creating with assembly code. Failed command: %s\n", cmd.getAlias()); + 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. + * Note: Any update to the directory structure of the data needs to be reflected here. + */ +enum { + DATA_PREFIX_BRKITR, + DATA_PREFIX_COLL, + DATA_PREFIX_CURR, + DATA_PREFIX_LANG, + DATA_PREFIX_RBNF, + DATA_PREFIX_REGION, + DATA_PREFIX_TRANSLIT, + DATA_PREFIX_ZONE, + DATA_PREFIX_UNIT, + DATA_PREFIX_LENGTH +}; + +const static char DATA_PREFIX[DATA_PREFIX_LENGTH][10] = { + "brkitr", + "coll", + "curr", + "lang", + "rbnf", + "region", + "translit", + "zone", + "unit" +}; + +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] = ""; + FileStream *icudtAllFile = nullptr; + + snprintf(icudtAll, sizeof(icudtAll), "%s%s%sall.c", + o->tmpDir, + PKGDATA_FILE_SEP_STRING, + libFileNames[LIB_FILE]); + /* Remove previous icudtall.c file. */ + if (T_FileStream_file_exists(icudtAll) && (result = remove(icudtAll)) != 0) { + fprintf(stderr, "Unable to remove old icudtall file: %s\n", icudtAll); + return result; + } + + if((icudtAllFile = T_FileStream_open(icudtAll, "w"))==nullptr) { + fprintf(stderr, "Unable to write to icudtall file: %s\n", icudtAll); + return result; + } +#endif + + if (list == nullptr || listNames == nullptr) { + /* list and listNames should never be nullptr since we are looping through the CharList with + * the given size. + */ + return -1; + } + + if ((cmd = (char *)uprv_malloc((listSize + 2) * SMALL_BUFFER_MAX_SIZE)) == nullptr) { + fprintf(stderr, "Unable to allocate memory for cmd.\n"); + return -1; + } else if ((buffer = (char *)uprv_malloc((listSize + 1) * SMALL_BUFFER_MAX_SIZE)) == nullptr) { + 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 initializes the buffer. */ + createCommonDataFile(o->tmpDir, o->shortName, o->entryName, nullptr, 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'; + + sprintf(cmd, "%s %s -o %s %s", + pkgDataFlags[COMPILER], + pkgDataFlags[LIBFLAGS], + tempObjectFile, + gencmnFile); + + result = runCommand(cmd); + if (result != 0) { + break; + } + + sprintf(buffer, "%s",tempObjectFile); +#endif + } else { + char newName[SMALL_BUFFER_MAX_SIZE]; + char dataName[SMALL_BUFFER_MAX_SIZE]; + char dataDirName[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++) { + dataDirName[0] = 0; + sprintf(dataDirName, "%s%s", DATA_PREFIX[n], PKGDATA_FILE_SEP_STRING); + /* If the name contains a prefix (indicating directory), alter the new name accordingly. */ + pSubstring = uprv_strstr(name, dataDirName); + if (pSubstring != nullptr) { + char newNameTmp[SMALL_BUFFER_MAX_SIZE] = ""; + const char *p = name + uprv_strlen(dataDirName); + for (int32_t i = 0;;i++) { + if (p[i] == '.') { + newNameTmp[i] = '_'; + continue; + } + newNameTmp[i] = p[i]; + if (p[i] == 0) { + break; + } + } + auto ret = snprintf(newName, + sizeof(newName), + "%s_%s", + DATA_PREFIX[n], + newNameTmp); + (void)ret; + U_ASSERT(0 <= ret && ret < SMALL_BUFFER_MAX_SIZE); + ret = snprintf(dataName, + sizeof(dataName), + "%s_%s", + o->shortName, + DATA_PREFIX[n]); + (void)ret; + U_ASSERT(0 <= ret && ret < SMALL_BUFFER_MAX_SIZE); + } + if (newName[0] != 0) { + break; + } + } + + if(o->verbose) { + printf("# Generating %s \n", gencmnFile); + } + + writeCCode( + file, + o->tmpDir, + nullptr, + dataName[0] != 0 ? dataName : o->shortName, + newName[0] != 0 ? newName : nullptr, + gencmnFile, + sizeof(gencmnFile)); + +#ifdef USE_SINGLE_CCODE_FILE + sprintf(cmd, "#include \"%s\"\n", gencmnFile); + T_FileStream_writeLine(icudtAllFile, cmd); + /* don't delete the file */ +#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 = runCommand(cmd); + if (result != 0) { + fprintf(stderr, "Error creating library without assembly code. Failed command: %s\n", cmd); + break; + } + + uprv_strcat(buffer, " "); + uprv_strcat(buffer, tempObjectFile); + +#endif + + if (i > 0) { + list = list->next; + listNames = listNames->next; + } + } + +#ifdef USE_SINGLE_CCODE_FILE + T_FileStream_close(icudtAllFile); + uprv_strcpy(tempObjectFile, icudtAll); + tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o'; + + sprintf(cmd, "%s %s -I. -o %s %s", + pkgDataFlags[COMPILER], + pkgDataFlags[LIBFLAGS], + tempObjectFile, + icudtAll); + + result = runCommand(cmd); + if (result == 0) { + uprv_strcat(buffer, " "); + uprv_strcat(buffer, tempObjectFile); + } else { + fprintf(stderr, "Error creating library without assembly code. Failed command: %s\n", cmd); + } +#endif + + if (result == 0) { + /* Generate the library file. */ +#if U_PLATFORM == U_PF_OS390 + result = pkg_generateLibraryFile(targetDir, mode, buffer, cmd, (o->pdsbuild && IN_DLL_MODE(mode))); +#else + result = pkg_generateLibraryFile(targetDir,mode, buffer, cmd); +#endif + } + + uprv_free(buffer); + uprv_free(cmd); + + return result; +} +#endif + +#ifdef WINDOWS_WITH_MSVC +#define LINK_CMD "link.exe /nologo /release /out:" +#define LINK_FLAGS "/NXCOMPAT /DYNAMICBASE /DLL /NOENTRY /MANIFEST:NO /implib:" + +#define LINK_EXTRA_UWP_FLAGS "/APPCONTAINER " +#define LINK_EXTRA_UWP_FLAGS_X86_ONLY "/SAFESEH " + +#define LINK_EXTRA_FLAGS_MACHINE "/MACHINE:" +#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) { + int32_t result = 0; + char cmd[LARGE_BUFFER_MAX_SIZE]; + if (IN_STATIC_MODE(mode)) { + char staticLibFilePath[SMALL_BUFFER_MAX_SIZE] = ""; + +#ifdef CYGWINMSVC + snprintf(staticLibFilePath, sizeof(staticLibFilePath), "%s%s%s%s%s", + o->targetDir, + PKGDATA_FILE_SEP_STRING, + pkgDataFlags[LIBPREFIX], + o->libName, + LIB_EXT); +#else + snprintf(staticLibFilePath, sizeof(staticLibFilePath), "%s%s%s%s%s", + o->targetDir, + PKGDATA_FILE_SEP_STRING, + (strstr(o->libName, "icudt") ? "s" : ""), + o->libName, + LIB_EXT); +#endif + + snprintf(cmd, sizeof(cmd), "%s\"%s\" \"%s\"", + LIB_CMD, + staticLibFilePath, + gencFilePath); + } else if (IN_DLL_MODE(mode)) { + char dllFilePath[SMALL_BUFFER_MAX_SIZE] = ""; + char libFilePath[SMALL_BUFFER_MAX_SIZE] = ""; + char resFilePath[SMALL_BUFFER_MAX_SIZE] = ""; + char tmpResFilePath[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); + +#ifdef CYGWINMSVC + uprv_strcat(libFilePath, o->libName); + uprv_strcat(libFilePath, ".lib"); + + uprv_strcat(dllFilePath, o->libName); + uprv_strcat(dllFilePath, o->version); +#else + if (strstr(o->libName, "icudt")) { + uprv_strcat(libFilePath, LIB_FILE); + } else { + uprv_strcat(libFilePath, o->libName); + uprv_strcat(libFilePath, ".lib"); + } + uprv_strcat(dllFilePath, o->entryName); +#endif + uprv_strcat(dllFilePath, DLL_EXT); + + uprv_strcpy(tmpResFilePath, o->tmpDir); + uprv_strcat(tmpResFilePath, PKGDATA_FILE_SEP_STRING); + uprv_strcat(tmpResFilePath, ICUDATA_RES_FILE); + + if (T_FileStream_file_exists(tmpResFilePath)) { + snprintf(resFilePath, sizeof(resFilePath), "\"%s\"", tmpResFilePath); + } + + /* 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))) { + if(o->verbose) { + printf("# Not rebuilding %s - up to date.\n", gencFilePath); + } + return 0; + } + + char extraFlags[SMALL_BUFFER_MAX_SIZE] = ""; +#ifdef WINDOWS_WITH_MSVC + if (options[WIN_UWP_BUILD].doesOccur) { + uprv_strcat(extraFlags, LINK_EXTRA_UWP_FLAGS); + + if (options[WIN_DLL_ARCH].doesOccur) { + if (uprv_strcmp(options[WIN_DLL_ARCH].value, "X86") == 0) { + uprv_strcat(extraFlags, LINK_EXTRA_UWP_FLAGS_X86_ONLY); + } + } + } + + if (options[WIN_DLL_ARCH].doesOccur) { + uprv_strcat(extraFlags, LINK_EXTRA_FLAGS_MACHINE); + uprv_strcat(extraFlags, options[WIN_DLL_ARCH].value); + } + +#endif + snprintf(cmd, sizeof(cmd), "%s\"%s\" %s %s\"%s\" \"%s\" %s", + LINK_CMD, + dllFilePath, + extraFlags, + LINK_FLAGS, + libFilePath, + gencFilePath, + resFilePath + ); + } + + result = runCommand(cmd, true); + if (result != 0) { + fprintf(stderr, "Error creating Windows DLL library. Failed command: %s\n", cmd); + } + + return result; +} +#endif + +static UPKGOptions *pkg_checkFlag(UPKGOptions *o) { +#if U_PLATFORM == U_PF_AIX + /* AIX needs a map file. */ + char *flag = nullptr; + int32_t length = 0; + char tmpbuffer[SMALL_BUFFER_MAX_SIZE]; + const char MAP_FILE_EXT[] = ".map"; + FileStream *f = nullptr; + char mapFile[SMALL_BUFFER_MAX_SIZE] = ""; + int32_t start = -1; + uint32_t count = 0; + const char rm_cmd[] = "rm -f all ;"; + + flag = pkgDataFlags[GENLIB]; + + /* This portion of the code removes 'rm -f all' in the GENLIB. + * Only occurs in AIX. + */ + if (uprv_strstr(flag, rm_cmd) != nullptr) { + char *tmpGenlibFlagBuffer = nullptr; + int32_t i, offset; + + length = static_cast(uprv_strlen(flag) + 1); + tmpGenlibFlagBuffer = (char *)uprv_malloc(length); + if (tmpGenlibFlagBuffer == nullptr) { + /* Memory allocation error */ + fprintf(stderr,"Unable to allocate buffer of size: %d.\n", length); + return nullptr; + } + + uprv_strcpy(tmpGenlibFlagBuffer, flag); + + offset = static_cast(uprv_strlen(rm_cmd)); + + for (i = 0; i < (length - offset); i++) { + flag[i] = tmpGenlibFlagBuffer[offset + i]; + } + + /* Zero terminate the string */ + flag[i] = 0; + + uprv_free(tmpGenlibFlagBuffer); + } + + flag = pkgDataFlags[BIR_FLAGS]; + length = static_cast(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 == nullptr) { + fprintf(stderr,"Unable to create map file: %s.\n", mapFile); + return nullptr; + } else { + snprintf(tmpbuffer, sizeof(tmpbuffer), "%s%s ", o->entryName, UDATA_CMN_INTERMEDIATE_SUFFIX); + + T_FileStream_writeLine(f, tmpbuffer); + + T_FileStream_close(f); + } + } +#elif U_PLATFORM == U_PF_CYGWIN || U_PLATFORM == U_PF_MINGW + /* Cygwin needs to change flag options. */ + char *flag = nullptr; + int32_t length = 0; + + flag = pkgDataFlags[GENLIB]; + length = static_cast(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 U_PLATFORM == U_PF_OS400 + /* OS/400 needs to fix the ld options (swap single quote with double quote) */ + char *flag = nullptr; + int32_t length = 0; + + flag = pkgDataFlags[GENLIB]; + length = static_cast(uprv_strlen(pkgDataFlags[GENLIB])); + + int32_t position = length - 1; + + for(int32_t i = 0; i < length; i++) { + if (flag[i] == '\'') { + flag[i] = '\"'; + } + } +#endif + // Don't really need a return value, just need to stop compiler warnings about + // the unused parameter 'o' on platforms where it is not otherwise used. + return o; +} + +static void loadLists(UPKGOptions *o, UErrorCode *status) +{ + CharList *l, *tail = nullptr, *tail2 = nullptr; + FileStream *in; + char line[16384]; + char *linePtr, *lineNext; + const uint32_t lineMax = 16300; + char *tmp; + int32_t tmpLength = 0; + char *s; + int32_t ln=0; /* line number */ + + for(l = o->fileListFiles; l; l = l->next) { + if(o->verbose) { + fprintf(stdout, "# pkgdata: 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))!=nullptr) { /* 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; + /* On z/OS, disable call to isspace (#9996). Investigate using uprv_isspace instead (#9999) */ +#if U_PLATFORM != U_PF_OS390 + while(isspace(*linePtr)) { + linePtr++; + } +#endif + 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 = nullptr; + + while(linePtr && *linePtr) { /* process space-separated items */ + while(*linePtr == ' ') { + linePtr++; + } + /* Find the next quote */ + if(linePtr[0] == '"') + { + lineNext = uprv_strchr(linePtr+1, '"'); + if(lineNext == nullptr) { + 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) || s[0] == '.') { + 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); + } + /* The +5 is to add a little extra space for, among other things, PKGDATA_FILE_SEP_STRING */ + tmpLength = static_cast(uprv_strlen(o->srcDir) + uprv_strlen(s) + 5); + if((tmp = (char *)uprv_malloc(tmpLength)) == nullptr) { + fprintf(stderr, "pkgdata: Error: Unable to allocate tmp buffer size: %d\n", tmpLength); + exit(U_MEMORY_ALLOCATION_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, tmp); + linePtr = lineNext; + } /* for each entry on line */ + } /* for each line */ + T_FileStream_close(in); + } /* for each file list file */ +} + +/* Helper for pkg_getPkgDataPath() */ +#if U_HAVE_POPEN +static UBool getPkgDataPath(const char *cmd, UBool verbose, char *buf, size_t items) { + icu::CharString cmdBuf; + UErrorCode status = U_ZERO_ERROR; + icu::LocalPipeFilePointer p; + size_t n; + + cmdBuf.append(cmd, status); + if (verbose) { + fprintf(stdout, "# Calling: %s\n", cmdBuf.data()); + } + p.adoptInstead( popen(cmdBuf.data(), "r") ); + + if (p.isNull() || (n = fread(buf, 1, items-1, p.getAlias())) <= 0) { + fprintf(stderr, "%s: Error calling '%s'\n", progname, cmd); + *buf = 0; + return false; + } + + return true; +} +#endif + +/* Get path to pkgdata.inc. Try pkg-config first, falling back to icu-config. */ +static int32_t pkg_getPkgDataPath(UBool verbose, UOption *option) { +#if U_HAVE_POPEN + static char buf[512] = ""; + UBool pkgconfigIsValid = true; + const char *pkgconfigCmd = "pkg-config --variable=pkglibdir icu-uc"; + const char *icuconfigCmd = "icu-config --incpkgdatafile"; + const char *pkgdata = "pkgdata.inc"; + + if (!getPkgDataPath(pkgconfigCmd, verbose, buf, UPRV_LENGTHOF(buf))) { + if (!getPkgDataPath(icuconfigCmd, verbose, buf, UPRV_LENGTHOF(buf))) { + fprintf(stderr, "%s: icu-config not found. Fix PATH or specify -O option\n", progname); + return -1; + } + + pkgconfigIsValid = false; + } + + for (int32_t length = strlen(buf) - 1; length >= 0; length--) { + if (buf[length] == '\n' || buf[length] == ' ') { + buf[length] = 0; + } else { + break; + } + } + + if (!*buf) { + fprintf(stderr, "%s: Unable to locate pkgdata.inc. Unable to parse the results of '%s'. Check paths or use the -O option to specify the path to pkgdata.inc.\n", progname, pkgconfigIsValid ? pkgconfigCmd : icuconfigCmd); + return -1; + } + + if (pkgconfigIsValid) { + uprv_strcat(buf, U_FILE_SEP_STRING); + uprv_strcat(buf, pkgdata); + } + + buf[strlen(buf)] = 0; + + option->value = buf; + option->doesOccur = true; + + return 0; +#else + return -1; +#endif +} + +#ifdef CAN_WRITE_OBJ_CODE + /* Create optMatchArch for genccode architecture detection */ +static void pkg_createOptMatchArch(char *optMatchArch) { +#if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN) + const char* code = "void oma(){}"; + const char* source = "oma.c"; + const char* obj = "oma.obj"; + FileStream* stream = nullptr; + + stream = T_FileStream_open(source,"w"); + if (stream != nullptr) { + T_FileStream_writeLine(stream, code); + T_FileStream_close(stream); + + char cmd[LARGE_BUFFER_MAX_SIZE]; + snprintf(cmd, sizeof(cmd), "%s %s -o %s", + pkgDataFlags[COMPILER], + source, + obj); + + if (runCommand(cmd) == 0){ + sprintf(optMatchArch, "%s", obj); + } + else { + fprintf(stderr, "Failed to compile %s\n", source); + } + if(!T_FileStream_remove(source)){ + fprintf(stderr, "T_FileStream_remove failed to delete %s\n", source); + } + } + else { + fprintf(stderr, "T_FileStream_open failed to open %s for writing\n", source); + } +#endif +} +static void pkg_destroyOptMatchArch(char *optMatchArch) { + if(T_FileStream_file_exists(optMatchArch) && !T_FileStream_remove(optMatchArch)){ + fprintf(stderr, "T_FileStream_remove failed to delete %s\n", optMatchArch); + } +} +#endif diff --git a/tools/icu/patches/75/source/tools/toolutil/pkg_genc.cpp b/tools/icu/patches/75/source/tools/toolutil/pkg_genc.cpp new file mode 100644 index 00000000000000..d51a52c8fff13c --- /dev/null +++ b/tools/icu/patches/75/source/tools/toolutil/pkg_genc.cpp @@ -0,0 +1,1428 @@ +// © 2016 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html +/****************************************************************************** + * Copyright (C) 2009-2016, International Business Machines + * Corporation and others. All Rights Reserved. + ******************************************************************************* + */ +#include "unicode/utypes.h" + +#if U_PLATFORM_HAS_WIN32_API +# define VC_EXTRALEAN +# define WIN32_LEAN_AND_MEAN +# define NOUSER +# define NOSERVICE +# define NOIME +# define NOMCX +#include +#include +# if defined(__clang__) +# include +# endif +# ifdef __GNUC__ +# define WINDOWS_WITH_GNUC +# endif +#endif + +#if U_PLATFORM_IS_LINUX_BASED && U_HAVE_ELF_H +# define U_ELF +#endif + +#ifdef U_ELF +# include +# 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 +#include +#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" +#include "filetools.h" +#include "charstr.h" +#include "unicode/errorcode.h" + +#define MAX_COLUMN ((uint32_t)(0xFFFFFFFFU)) + +#define HEX_0X 0 /* 0x1234 */ +#define HEX_0H 1 /* 01234h */ + +/* prototypes --------------------------------------------------------------- */ +static void +getOutFilename( + const char *inFilename, + const char *destdir, + char *outFilename, + int32_t outFilenameCapacity, + char *entryName, + int32_t entryNameCapacity, + 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); + +#if U_PLATFORM == U_PF_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,@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[] = { + /* For gcc assemblers, the meaning of .align changes depending on the */ + /* hardware, so we use .balign 16 which always means 16 bytes. */ + /* https://sourceware.org/binutils/docs/as/Pseudo-Ops.html */ + {"gcc", + ".globl %s\n" + "\t.section .note.GNU-stack,\"\",%%progbits\n" + "#ifdef __CET__\n" + "# include \n" + "#endif\n" + "\t.section .rodata\n" + "\t.balign 16\n" + "#ifdef U_HIDE_DATA_SYMBOL\n" + "\t.hidden %s\n" + "#endif\n" + "\t.type %s,%%object\n" + "%s:\n\n", + + ".long ",".size %s, .-%s\n",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" + "#ifdef U_HIDE_DATA_SYMBOL\n" + "\t.private_extern _%s\n" + "#endif\n" + "\t.data\n" + "\t.const\n" + "\t.balign 16\n" + "_%s:\n\n", + + ".long ","",HEX_0X + }, + /* macOS PPC should use `.p2align 4` instead `.balign 16` because is + * unknown pseudo ops for such legacy system*/ + {"gcc-darwin-ppc", + /*"\t.section __TEXT,__text,regular,pure_instructions\n" + "\t.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32\n"*/ + ".globl _%s\n" + "#ifdef U_HIDE_DATA_SYMBOL\n" + "\t.private_extern _%s\n" + "#endif\n" + "\t.data\n" + "\t.const\n" + "\t.p2align 4\n" + "_%s:\n\n", + + ".long ","",HEX_0X + }, + {"gcc-cygwin", + ".globl _%s\n" + "\t.section .rodata\n" + "\t.balign 16\n" + "_%s:\n\n", + + ".long ","",HEX_0X + }, + {"gcc-mingw64", + ".globl %s\n" + "\t.section .rodata\n" + "\t.balign 16\n" + "%s:\n\n", + + ".long ","",HEX_0X + }, +/* 16 bytes alignment. */ +/* http://docs.oracle.com/cd/E19641-01/802-1947/802-1947.pdf */ + {"sun", + "\t.section \".rodata\"\n" + "\t.align 16\n" + ".globl %s\n" + "%s:\n", + + ".word ","",HEX_0X + }, +/* 16 bytes alignment for sun-x86. */ +/* http://docs.oracle.com/cd/E19963-01/html/821-1608/eoiyg.html */ + {"sun-x86", + "Drodata.rodata:\n" + "\t.type Drodata.rodata,@object\n" + "\t.size Drodata.rodata,0\n" + "\t.globl %s\n" + "\t.align 16\n" + "%s:\n", + + ".4byte ","",HEX_0X + }, +/* 1<<4 bit alignment for aix. */ +/* http://pic.dhe.ibm.com/infocenter/aix/v6r1/index.jsp?topic=%2Fcom.ibm.aix.aixassem%2Fdoc%2Falangref%2Fidalangref_csect_pseudoop.htm */ + {"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,@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 + }, +/* align 16 bytes */ +/* http://msdn.microsoft.com/en-us/library/dwa9fwef.aspx */ + {"nasm", + "global %s\n" +#if defined(_WIN32) + "section .rdata align=16\n" +#else + "section .rodata align=16\n" +#endif + "%s:\n", + " dd ","",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 + }, + { "masm64", + "\tTITLE %s\n" + "; generated by genccode\n" + "\tPUBLIC _%s\n" + "ICUDATA_%s\tSEGMENT READONLY '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 < UPRV_LENGTHOF(assemblyHeader); 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 UBool U_EXPORT2 +checkCpuArchitecture(const char* optCpuArch) { + return strcmp(optCpuArch, "x64") == 0 || strcmp(optCpuArch, "x86") == 0 || strcmp(optCpuArch, "arm64") == 0; +} + + +U_CAPI void U_EXPORT2 +printAssemblyHeadersToStdErr() { + int32_t idx; + fprintf(stderr, "%s", assemblyHeader[0].name); + for (idx = 1; idx < UPRV_LENGTHOF(assemblyHeader); 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, + size_t outFilePathCapacity) { + uint32_t column = MAX_COLUMN; + char entry[96]; + union { + uint32_t uint32s[1024]; + char chars[4096]; + } buffer; + FileStream *in, *out; + size_t i, length, count; + + in=T_FileStream_open(filename, "rb"); + if(in==nullptr) { + fprintf(stderr, "genccode: unable to open input file %s\n", filename); + exit(U_FILE_ACCESS_ERROR); + } + + const char* newSuffix = nullptr; + + if (uprv_strcmp(assemblyHeader[assemblyHeaderIndex].name, "masm") == 0) { + newSuffix = ".masm"; + } + else if (uprv_strcmp(assemblyHeader[assemblyHeaderIndex].name, "nasm") == 0) { + newSuffix = ".asm"; + } else { + newSuffix = ".S"; + } + + getOutFilename( + filename, + destdir, + buffer.chars, + sizeof(buffer.chars), + entry, + sizeof(entry), + newSuffix, + optFilename); + out=T_FileStream_open(buffer.chars, "w"); + if(out==nullptr) { + fprintf(stderr, "genccode: unable to open output file %s\n", buffer.chars); + exit(U_FILE_ACCESS_ERROR); + } + + if (outFilePath != nullptr) { + if (uprv_strlen(buffer.chars) >= outFilePathCapacity) { + fprintf(stderr, "genccode: filename too long\n"); + exit(U_ILLEGAL_ARGUMENT_ERROR); + } + uprv_strcpy(outFilePath, buffer.chars); +#if defined (WINDOWS_WITH_GNUC) && U_PLATFORM != U_PF_CYGWIN + /* Need to fix the file separator character when using MinGW. */ + swapFileSepChar(outFilePath, U_FILE_SEP_CHAR, '/'); +#endif + } + + if(optEntryPoint != nullptr) { + 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= sizeof(buffer.chars)) { + fprintf(stderr, "genccode: entry name too long (long filename?)\n"); + exit(U_ILLEGAL_ARGUMENT_ERROR); + } + T_FileStream_writeLine(out, buffer.chars); + T_FileStream_writeLine(out, assemblyHeader[assemblyHeaderIndex].beginLine); + + for(;;) { + memset(buffer.uint32s, 0, sizeof(buffer.uint32s)); + length=T_FileStream_read(in, buffer.uint32s, sizeof(buffer.uint32s)); + if(length==0) { + break; + } + for(i=0; i<(length/sizeof(buffer.uint32s[0])); i++) { + // TODO: What if the last read sees length not as a multiple of 4? + column = write32(out, buffer.uint32s[i], column); + } + } + + T_FileStream_writeLine(out, "\n"); + + count = snprintf( + buffer.chars, sizeof(buffer.chars), + assemblyHeader[assemblyHeaderIndex].footer, + entry, entry, entry, entry, + entry, entry, entry, entry); + if (count >= sizeof(buffer.chars)) { + fprintf(stderr, "genccode: entry name too long (long filename?)\n"); + exit(U_ILLEGAL_ARGUMENT_ERROR); + } + T_FileStream_writeLine(out, buffer.chars); + + 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 *optEntryPoint, + const char *optName, + const char *optFilename, + char *outFilePath, + size_t outFilePathCapacity) { + uint32_t column = MAX_COLUMN; + char buffer[4096], entry[96]; + FileStream *in, *out; + size_t i, length, count; + + in=T_FileStream_open(filename, "rb"); + if(in==nullptr) { + fprintf(stderr, "genccode: unable to open input file %s\n", filename); + exit(U_FILE_ACCESS_ERROR); + } + + if(optName != nullptr) { /* prepend 'icudt28_' */ + // +2 includes the _ and the NUL + if (uprv_strlen(optName) + 2 > sizeof(entry)) { + fprintf(stderr, "genccode: entry name too long (long filename?)\n"); + exit(U_ILLEGAL_ARGUMENT_ERROR); + } + strcpy(entry, optName); + strcat(entry, "_"); + } else { + entry[0] = 0; + } + + getOutFilename( + filename, + destdir, + buffer, + static_cast(sizeof(buffer)), + entry + uprv_strlen(entry), + static_cast(sizeof(entry) - uprv_strlen(entry)), + ".c", + optFilename); + + if (outFilePath != nullptr) { + if (uprv_strlen(buffer) >= outFilePathCapacity) { + fprintf(stderr, "genccode: filename too long\n"); + exit(U_ILLEGAL_ARGUMENT_ERROR); + } + uprv_strcpy(outFilePath, buffer); +#if defined (WINDOWS_WITH_GNUC) && U_PLATFORM != U_PF_CYGWIN + /* Need to fix the file separator character when using MinGW. */ + swapFileSepChar(outFilePath, U_FILE_SEP_CHAR, '/'); +#endif + } + + out=T_FileStream_open(buffer, "w"); + if(out==nullptr) { + fprintf(stderr, "genccode: unable to open output file %s\n", buffer); + exit(U_FILE_ACCESS_ERROR); + } + + if(optEntryPoint != nullptr) { + 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= sizeof(buffer)) { + fprintf(stderr, "genccode: entry name too long (long filename?)\n"); + exit(U_ILLEGAL_ARGUMENT_ERROR); + } + T_FileStream_writeLine(out, buffer); + + for(;;) { + length=T_FileStream_read(in, buffer, sizeof(buffer)); + if(length==0) { + break; + } + for(i=0; i= sizeof(buffer)) { + fprintf(stderr, "genccode: entry name too long (long filename?)\n"); + exit(U_ILLEGAL_ARGUMENT_ERROR); + } + T_FileStream_writeLine(out, buffer); + + for(;;) { + length=T_FileStream_read(in, buffer, sizeof(buffer)); + if(length==0) { + break; + } + for(i=0; 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; +} + +#if U_PLATFORM == U_PF_OS400 +static uint32_t +write8str(FileStream *out, uint8_t byte, uint32_t column) { + char s[8]; + + if (byte > 7) + snprintf(s, sizeof(s), "\\x%X", byte); + else + snprintf(s, sizeof(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, + int32_t outFilenameCapacity, + char *entryName, + int32_t entryNameCapacity, + const char *newSuffix, + const char *optFilename) { + const char *basename=findBasename(inFilename), *suffix=uprv_strrchr(basename, '.'); + + icu::CharString outFilenameBuilder; + icu::CharString entryNameBuilder; + icu::ErrorCode status; + + /* copy path */ + if(destdir!=nullptr && *destdir!=0) { + outFilenameBuilder.append(destdir, status); + outFilenameBuilder.ensureEndsWithFileSeparator(status); + } else { + outFilenameBuilder.append(inFilename, static_cast(basename - inFilename), status); + } + inFilename=basename; + + if(suffix==nullptr) { + /* the filename does not have a suffix */ + entryNameBuilder.append(inFilename, status); + if(optFilename != nullptr) { + outFilenameBuilder.append(optFilename, status); + } else { + outFilenameBuilder.append(inFilename, status); + } + outFilenameBuilder.append(newSuffix, status); + } else { + int32_t saveOutFilenameLength = outFilenameBuilder.length(); + /* copy basename */ + while(inFilename= outFilenameCapacity) { + fprintf(stderr, "genccode: output filename too long\n"); + exit(U_ILLEGAL_ARGUMENT_ERROR); + } + + if (entryNameBuilder.length() >= entryNameCapacity) { + fprintf(stderr, "genccode: entry name too long (long filename?)\n"); + exit(U_ILLEGAL_ARGUMENT_ERROR); + } + + outFilenameBuilder.extract(outFilename, outFilenameCapacity, status); + entryNameBuilder.extract(entryName, entryNameCapacity, status); +} + +#ifdef CAN_GENERATE_OBJECTS +static void +getArchitecture( + uint16_t *pCPU, + uint16_t *pBits, + UBool *pIsBigEndian, + const char *optMatchArch, + [[maybe_unused]] const char *optCpuArch) { + union { + char bytes[2048]; +#ifdef U_ELF + Elf32_Ehdr header32; + /* Elf32_Ehdr and ELF64_Ehdr are identical for the necessary fields. */ +#elif U_PLATFORM_HAS_WIN32_API + IMAGE_FILE_HEADER header; +#endif + } buffer; + + const char *filename; + FileStream *in; + int32_t length; + +#ifdef U_ELF + +#elif U_PLATFORM_HAS_WIN32_API + const IMAGE_FILE_HEADER *pHeader; +#else +# error "Unknown platform for CAN_GENERATE_OBJECTS." +#endif + + if(optMatchArch != nullptr) { + 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 U_PLATFORM_HAS_WIN32_API + // Windows always runs in little-endian mode. + *pIsBigEndian = false; + + // Note: The various _M_ macros are predefined by the MSVC compiler based + // on the target compilation architecture. + // https://docs.microsoft.com/cpp/preprocessor/predefined-macros + + // link.exe will link an IMAGE_FILE_MACHINE_UNKNOWN data-only .obj file + // no matter what architecture it is targeting (though other values are + // required to match). Unfortunately, the variable name decoration/mangling + // is slightly different on x86, which means we can't use the UNKNOWN type + // for all architectures though. +# if defined(_M_IX86) + *pCPU = IMAGE_FILE_MACHINE_I386; +# else + // Linker for ClangCL doesn't handle IMAGE_FILE_MACHINE_UNKNOWN the same as + // linker for MSVC. Because of this optCpuArch is used to define the CPU + // architecture in that case. While _M_AMD64 and _M_ARM64 could be used, + // this would potentially be problematic when cross-compiling as this code + // would most likely be ran on host machine to generate the .obj file for + // the target architecture. +# if defined(__clang__) + if (strcmp(optCpuArch, "x64") == 0) { + *pCPU = IMAGE_FILE_MACHINE_AMD64; + } else if (strcmp(optCpuArch, "x86") == 0) { + *pCPU = IMAGE_FILE_MACHINE_I386; + } else if (strcmp(optCpuArch, "arm64") == 0) { + *pCPU = IMAGE_FILE_MACHINE_ARM64; + } else { + std::terminate(); // Unreachable. + } +# else + *pCPU = IMAGE_FILE_MACHINE_UNKNOWN; +# endif +# endif +# if defined(_M_IA64) || defined(_M_AMD64) || defined (_M_ARM64) + *pBits = 64; // Doesn't seem to be used for anything interesting though? +# elif defined(_M_IX86) || defined(_M_ARM) + *pBits = 32; +# else +# error "Unknown platform for CAN_GENERATE_OBJECTS." +# endif +#else +# error "Unknown platform for CAN_GENERATE_OBJECTS." +#endif + return; + } + + in=T_FileStream_open(filename, "rb"); + if(in==nullptr) { + fprintf(stderr, "genccode: unable to open match-arch file %s\n", filename); + exit(U_FILE_ACCESS_ERROR); + } + length=T_FileStream_read(in, buffer.bytes, sizeof(buffer.bytes)); + +#ifdef U_ELF + if(length<(int32_t)sizeof(Elf32_Ehdr)) { + fprintf(stderr, "genccode: match-arch file %s is too short\n", filename); + exit(U_UNSUPPORTED_ERROR); + } + if( + buffer.header32.e_ident[0]!=ELFMAG0 || + buffer.header32.e_ident[1]!=ELFMAG1 || + buffer.header32.e_ident[2]!=ELFMAG2 || + buffer.header32.e_ident[3]!=ELFMAG3 || + buffer.header32.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= buffer.header32.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)(buffer.header32.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=buffer.header32.e_machine; +#elif U_PLATFORM_HAS_WIN32_API + if(lengthMachine; + /* + * 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 *optCpuArch, + const char *optFilename, + char *outFilePath, + size_t outFilePathCapacity, + UBool optWinDllExport) { + /* common variables */ + char buffer[4096], entry[96]={ 0 }; + FileStream *in, *out; + const char *newSuffix; + int32_t i, entryLength, length, size, entryOffset=0, entryLengthOffset=0; + + uint16_t cpu, bits; + UBool makeBigEndian; + + (void)optWinDllExport; /* unused except Windows */ + + /* 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, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 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 U_PLATFORM_HAS_WIN32_API + 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, optCpuArch); + if (optMatchArch) + { + printf("genccode: --match-arch cpu=%hu bits=%hu big-endian=%d\n", cpu, bits, makeBigEndian); + } + else + { + printf("genccode: using architecture cpu=%hu bits=%hu big-endian=%d\n", cpu, bits, makeBigEndian); + } +#if U_PLATFORM_HAS_WIN32_API + if(cpu==IMAGE_FILE_MACHINE_I386) { + entryOffset=1; + } +#endif + + in=T_FileStream_open(filename, "rb"); + if(in==nullptr) { + 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, + sizeof(buffer), + entry + entryOffset, + sizeof(entry) - entryOffset, + newSuffix, + optFilename); + + if (outFilePath != nullptr) { + if (uprv_strlen(buffer) >= outFilePathCapacity) { + fprintf(stderr, "genccode: filename too long\n"); + exit(U_ILLEGAL_ARGUMENT_ERROR); + } + uprv_strcpy(outFilePath, buffer); + } + + if(optEntryPoint != nullptr) { + 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