diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /intl/icu/source/tools/pkgdata | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream.tar.xz firefox-esr-upstream.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'intl/icu/source/tools/pkgdata')
-rw-r--r-- | intl/icu/source/tools/pkgdata/Makefile.in | 102 | ||||
-rw-r--r-- | intl/icu/source/tools/pkgdata/pkgdata.1.in | 260 | ||||
-rw-r--r-- | intl/icu/source/tools/pkgdata/pkgdata.cpp | 2293 | ||||
-rw-r--r-- | intl/icu/source/tools/pkgdata/pkgdata.vcxproj | 84 | ||||
-rw-r--r-- | intl/icu/source/tools/pkgdata/pkgdata.vcxproj.filters | 30 | ||||
-rw-r--r-- | intl/icu/source/tools/pkgdata/pkgtypes.c | 303 | ||||
-rw-r--r-- | intl/icu/source/tools/pkgdata/pkgtypes.h | 172 | ||||
-rw-r--r-- | intl/icu/source/tools/pkgdata/sources.txt | 2 |
8 files changed, 3246 insertions, 0 deletions
diff --git a/intl/icu/source/tools/pkgdata/Makefile.in b/intl/icu/source/tools/pkgdata/Makefile.in new file mode 100644 index 0000000000..4777998852 --- /dev/null +++ b/intl/icu/source/tools/pkgdata/Makefile.in @@ -0,0 +1,102 @@ +## Makefile.in for ICU - tools/pkgdata +## Copyright (C) 2016 and later: Unicode, Inc. and others. +## License & terms of use: http://www.unicode.org/copyright.html +## Copyright (c) 1999-2011, International Business Machines Corporation and +## others. All Rights Reserved. +## Steven R. Loomis + +## Source directory information +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ + +top_builddir = ../.. + +include $(top_builddir)/icudefs.mk + +## Build directory information +subdir = tools/pkgdata + +TARGET_STUB_NAME = pkgdata + +SECTION = 1 + +MAN_FILES = $(TARGET_STUB_NAME).$(SECTION) + +## Extra files to remove for 'make clean' +CLEANFILES = *~ $(DEPS) $(MAN_FILES) + +ifneq ($(PKGDATA_DEFS),) +DEFS += $(PKGDATA_DEFS) +endif + +## Target information +TARGET = $(BINDIR)/$(TARGET_STUB_NAME)$(EXEEXT) + +CPPFLAGS += -I$(srcdir) -I$(top_srcdir)/common -I$(srcdir)/../toolutil +DEFS += -DUDATA_SO_SUFFIX=\".$(SO)\" -DSTATIC_O=\"$(STATIC_O)\" +LIBS = $(LIBICUTOOLUTIL) $(LIBICUI18N) $(LIBICUUC) $(DEFAULT_LIBS) $(LIB_M) + +SOURCES = $(shell cat $(srcdir)/sources.txt) +OBJECTS = $(patsubst %.cpp,%.o,$(patsubst %.c,%.o, $(SOURCES))) + +DEPS = $(OBJECTS:.o=.d) + +## List of phony targets +.PHONY : all all-local install install-local clean clean-local \ +distclean distclean-local dist dist-local check check-local install-man + +## Clear suffix list +.SUFFIXES : + +## List of standard targets +all: all-local +install: install-local +clean: clean-local +distclean : distclean-local +dist: dist-local +check: all check-local + +all-local: $(TARGET) $(MAN_FILES) + +install-local: all-local install-man + $(MKINSTALLDIRS) $(DESTDIR)$(bindir) + $(INSTALL) $(TARGET) $(DESTDIR)$(bindir) + +install-man: $(MAN_FILES) + $(MKINSTALLDIRS) $(DESTDIR)$(mandir)/man$(SECTION) + $(INSTALL_DATA) $? $(DESTDIR)$(mandir)/man$(SECTION) + + +dist-local: + +clean-local: + test -z "$(CLEANFILES)" || $(RMV) $(CLEANFILES) + $(RMV) $(TARGET) $(OBJECTS) + +distclean-local: clean-local + $(RMV) Makefile + +check-local: all-local + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + +$(TARGET) : $(OBJECTS) + $(LINK.cc) $(OUTOPT)$@ $^ $(LIBS) + $(POST_BUILD_STEP) + + +%.$(SECTION): $(srcdir)/%.$(SECTION).in + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +ifeq (,$(MAKECMDGOALS)) +-include $(DEPS) +else +ifneq ($(patsubst %clean,,$(MAKECMDGOALS)),) +-include $(DEPS) +endif +endif + diff --git a/intl/icu/source/tools/pkgdata/pkgdata.1.in b/intl/icu/source/tools/pkgdata/pkgdata.1.in new file mode 100644 index 0000000000..cee92cab94 --- /dev/null +++ b/intl/icu/source/tools/pkgdata/pkgdata.1.in @@ -0,0 +1,260 @@ +.\" Hey, Emacs! This is -*-nroff-*- you know... +.\" +.\" pkgdata.1: manual page for the pkgdata utility +.\" +.\" Copyright (C) 2016 and later: Unicode, Inc. and others. +.\" License & terms of use: http://www.unicode.org/copyright.html +.\" Copyright (C) 2000-2009 IBM, Inc. and others. +.\" +.\" Manual page by Yves Arrouye <yves@realnames.com>. +.\" Modified by Michael Ow <mow@us.ibm.com>. +.\" +.TH PKGDATA 1 "6 February 2009" "ICU MANPAGE" "ICU @VERSION@ Manual" +.SH NAME +.B pkgdata +\- package data for use by ICU +.SH SYNOPSIS +.B pkgdata +[ +.BR "\-h\fP, \fB\-?\fP, \fB\-\-help" +] +[ +.BI "\-v\fP, \fB\-\-verbose" +] +[ +.BR "\-c\fP, \fB\-\-copyright" +| +.BI "\-C\fP, \fB\-\-comment" " comment" +] +[ +.BI "\-m\fP, \fB\-\-mode" " mode" +] +.BI "\-p\fP, \fB\-\-name" " name" +.BI "\-O\fP, \fB\-\-bldopt" " options" +[ +.BI "\-e\fP, \fB\-\-entrypoint" " name" +] +[ +.BI "\-r\fP, \fB\-\-revision" " version" +] +[ +.BI "\-F\fP, \fB\-\-rebuild" +] +[ +.BI "\-I\fP, \fB\-\-install" +] +[ +.BI "\-s\fP, \fB\-\-sourcedir" " source" +] +[ +.BI "\-d\fP, \fB\-\-destdir" " destination" +] +[ +.BI "\-T\fP, \fB\-\-tempdir" " directory" +] +[ +.IR file " .\|.\|." +] +.SH DESCRIPTION +.B pkgdata +takes a set of data files and packages them for use by ICU or +applications that use ICU. The typical reason to package files using +.B pkgdata +is to make their distribution easier and their loading by ICU faster +and less consuming of limited system resources such as file +descriptors. +Packaged data also allow applications to be distributed with fewer +resource files, or even with none at all if they link against the +packaged data directly. +.PP +.B pkgdata +supports a few different methods of packaging data that serve +different purposes. +.PP +The default packaging +.I mode +is +.BR common , +or +.BR archive . +In this mode, the different data files are bundled together as an +architecture-dependent file that can later be memory mapped for use by +ICU. Data packaged using this mode will be looked up under the ICU +data directory. Such packaging is easy to use for applications resource +bundles, for example, as long as the application can install the +packaged file in the ICU data directory. +.PP +Another packaging mode is the +.BR dll , +or +.BR library , +mode, where the data files are compiled into a shared library. ICU +used to be able to dynamically load these shared libraries, but as of +ICU 2.0, such support has been removed. This mode is still useful for +two main purposes: to build ICU itself, as the ICU data is packaged as +a shared library by default; and to build resource bundles that are +linked to the application that uses them. Such resource bundles can +then be placed anywhere where the system's dynamic linker will be +looking for shared libraries, instead of being forced to live inside +the ICU data directory. +.PP +The +.BR static +packaging mode is similar to the shared library one except that it +produces a static library. +.\" Note that many platforms are not able to +.\" dynamically load symbols from static object files, so for this reason +.\" .BR udata_setAppData() +.\" must be called +.\" to install this data. As a convenience, pkgdata will build a C source file +.\" and a header file. Given a data package named +.\" .IR name, in the output +.\" directory will be created +.\" .IR name .c +.\" and +.\" .IR name .h with the single +.\" function +.\" .BR "udata_install_\fcIname\fB(UErrorCode *err)" , +.\" where +.\" .I cname +.\" is +.\" .I name +.\" turned into a valid C identifier. +.\" The application need to call this function once. The error code returned +.\" is that of +.\" .BR udata_setAppData() . +.\" .PP +.\" Data pakackaged in a library, whether shared or static, +.\" Subsequently, the application can access this data by passing +.\" .I name for the +.\" .I path +.\" rgument to functions such as +.\" .BR Bures_open() . +.PP +Finally, +.B pkgdata +supports a +.B files +mode which simply copies the data files instead of packaging +them as a single file or library. This mode is mainly intended to +provide support for building ICU before it is packaged as separate +small packages for distribution with operating systems such as Debian +GNU/Linux for example. Please refer to the packaging documentation in +the ICU source distribution for further information on the use of this +mode. +.PP +.B pkgdata +builds, packages, installs, or cleans the appropriate data based on the options given +without the need to call GNU +.BR make +anymore. +.SH OPTIONS +.TP +.BR "\-h\fP, \fB\-?\fP, \fB\-\-help" +Print help about usage and exit. +.TP +.BR "\-v\fP, \fB\-\-verbose" +Display extra informative messages during execution. +.TP +.BR "\-c\fP, \fB\-\-copyright" +Include a copyright notice in the binary data. +.TP +.BI "\-C\fP, \fB\-\-comment" " comment" +Includes the specified +.I comment +in the resulting data instead of the ICU copyright notice. +.TP +.BI "\-m\fP, \fB\-\-mode" " mode" +Set the packaging +.I mode +to be used by +.BR pkgdata . +The different modes and their meaning are explained in the +.B DESCRIPTION +section above. The valid mode names are +.BR common +(or +.BR archive ), +.BR dll +(or +.BR library ), +and +.BR files . +.TP +.BI "\-O\fP, \fB\-\-bldopt" " options" +Specify options for the builder. The builder is used internally by +.B pkgdata +to generate the correct packaged file. Such options include, but are +not limited to, setting variables used by +.BR make (1) +during the build of the packaged file. Note: If +.BR icu-config +is available, then this option is not needed. +.TP +.BI "\-p\fP, \fB\-\-name" " name" +Set the packaged file name to +.IR name . +This name is also used as the default entry point name after having +been turned into a valid C identifier. +.TP +.BI "\-e\fP, \fB\-\-entrypoint" " name" +Set the data entry point (used for linking against the data in a +shared library form) to +.IR name . +The default entry point name is the name set by the +.BI "\-n\fP, \fB\-\-name" +option. +.TP +.BI "\-r\fP, \fB\-\-revision" " version" +Enable versioning of the shared library produced in +.BR dll , +or +.BR library , +mode. The version number has the format +.I major\fP.\fIminor\fP.\fIpatchlevel +and all parts except for +.I major +are optional. If only +.I major +is supplied then the version is +assumed to be +.IR major .0 +for versioning purposes. +.TP +.BI "\-F\fP, \fB\-\-rebuild" +Force the rebuilding of all data and their repackaging. +.TP +.BI "\-I\fP, \fB\-\-install" +Install the packaged file (or all the files in the +.B files +mode). If the variable +.B DESTDIR +is set it will be used for installation. +.TP +.BI "\-s\fP, \fB\-\-sourcedir" " source" +Set the source directory to +.IR source . +The default source directory is the current directory. +.TP +.BI "\-d\fP, \fB\-\-destdir" " destination" +Set the destination directory to +.IR destination . +The default destination directory is the current directory. +.TP +.BI "\-T\fP, \fB\-\-tempdir" " directory" +Set the directory used to generate temporary files to +.IR directory . +The default temporary directory is the same as the destination +directory +as set by the +.BI "\-d\fP, \fB\-\-destdir" +option. +.SH AUTHORS +Steven Loomis +.br +Yves Arrouye +.SH VERSION +@VERSION@ +.SH COPYRIGHT +Copyright (C) 2000-2009 IBM, Inc. and others. + diff --git a/intl/icu/source/tools/pkgdata/pkgdata.cpp b/intl/icu/source/tools/pkgdata/pkgdata.cpp new file mode 100644 index 0000000000..c2ac112f6e --- /dev/null +++ b/intl/icu/source/tools/pkgdata/pkgdata.cpp @@ -0,0 +1,2293 @@ +// © 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 <unistd.h> +#endif + +#include <stdio.h> +#include <stdlib.h> + +U_CDECL_BEGIN +#include "pkgtypes.h" +U_CDECL_END + +#if U_HAVE_POPEN + +using icu::LocalPointerBase; + +U_DEFINE_LOCAL_OPEN_POINTER(LocalPipeFilePointer, FILE, pclose); + +#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", 0, "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, <package>.dll"}, + { "common", "archive", "Generates just the common file, <package>.dat"}, + { "static", "static", "Generates one statically linked library, " LIB_PREFIX "<package>" UDATA_LIB_SUFFIX } +#else +#ifdef UDATA_SO_SUFFIX + { "dll", "library", "Generates one shared library, <package>" UDATA_SO_SUFFIX }, +#endif + { "common", "archive", "Generates one common data file, <package>.dat" }, + { "static", "static", "Generates one statically linked library, " LIB_PREFIX "<package>" UDATA_LIB_SUFFIX } +#endif +}; + +static UOption options[]={ + /*00*/ UOPTION_DEF( "name", 'p', UOPT_REQUIRES_ARG), + /*01*/ UOPTION_DEF( "bldopt", 'O', UOPT_REQUIRES_ARG), /* on Win32 it is release or debug */ + /*02*/ UOPTION_DEF( "mode", 'm', UOPT_REQUIRES_ARG), + /*03*/ UOPTION_HELP_H, /* -h */ + /*04*/ UOPTION_HELP_QUESTION_MARK, /* -? */ + /*05*/ UOPTION_VERBOSE, /* -v */ + /*06*/ UOPTION_COPYRIGHT, /* -c */ + /*07*/ UOPTION_DEF( "comment", 'C', UOPT_REQUIRES_ARG), + /*08*/ UOPTION_DESTDIR, /* -d */ + /*11*/ UOPTION_DEF( "rebuild", 'F', UOPT_NO_ARG), + /*12*/ UOPTION_DEF( "tempdir", 'T', UOPT_REQUIRES_ARG), + /*13*/ UOPTION_DEF( "install", 'I', UOPT_REQUIRES_ARG), + /*14*/ UOPTION_SOURCEDIR , + /*15*/ UOPTION_DEF( "entrypoint", 'e', UOPT_REQUIRES_ARG), + /*16*/ UOPTION_DEF( "revision", 'r', UOPT_REQUIRES_ARG), + /*17*/ UOPTION_DEF( "force-prefix", 'f', UOPT_NO_ARG), + /*18*/ UOPTION_DEF( "libname", 'L', UOPT_REQUIRES_ARG), + /*19*/ UOPTION_DEF( "quiet", 'q', UOPT_NO_ARG), + /*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. <ICUROOT> which contains the bin directory)", +#else + "Specify options for the builder.", +#endif + "Specify the mode of building (see below; default: common)", + "This usage text", + "This usage text", + "Make the output verbose", + "Use the standard ICU copyright", + "Use a custom comment (instead of the copyright)", + "Specify the destination directory for files", + "Force rebuilding of all data", + "Specify temporary dir (default: output dir)", + "Install the data (specify target)", + "Specify a custom source directory", + "Specify a custom entrypoint name (default: short name)", + "Specify a version when packaging in dll or static mode", + "Add package to all file names if not present", + "Library name to build (if different than package name)", + "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<UPRV_LENGTHOF(options);i++) { + fprintf(stderr, "%-5s -%c %s%-10s %s\n", + (i<1?"[REQ]":""), + options[i].shortName, + options[i].longName ? "or --" : " ", + options[i].longName ? options[i].longName : "", + options_help[i]); + } + + fprintf(stderr, "modes: (-m option)\n"); + for(i=0;i<UPRV_LENGTHOF(modes);i++) { + fprintf(stderr, " %-9s ", modes[i].name); + if (modes[i].alt_name) { + fprintf(stderr, "/ %-9s", modes[i].alt_name); + } else { + fprintf(stderr, " "); + } + fprintf(stderr, " %s\n", modes[i].desc); + } + return 1; + } + + /* OK, fill in the options struct */ + uprv_memset(&o, 0, sizeof(o)); + + o.mode = options[MODE].value; + o.version = options[REVISION].doesOccur ? options[REVISION].value : 0; + + o.shortName = options[NAME].value; + { + int32_t len = (int32_t)uprv_strlen(o.shortName); + char *csname, *cp; + const char *sp; + + cp = csname = (char *) uprv_malloc((len + 1 + 1) * sizeof(*o.cShortName)); + if (*(sp = o.shortName)) { + *cp++ = isalpha(*sp) ? * sp : '_'; + for (++sp; *sp; ++sp) { + *cp++ = isalnum(*sp) ? *sp : '_'; + } + } + *cp = 0; + + o.cShortName = csname; + } + + if(options[LIBNAME].doesOccur) { /* get libname from shortname, or explicit -L parameter */ + o.libName = options[LIBNAME].value; + } else { + o.libName = o.shortName; + } + + if(options[QUIET].doesOccur) { + o.quiet = true; + } else { + o.quiet = false; + } + + if(options[PDS_BUILD].doesOccur) { +#if U_PLATFORM == U_PF_OS390 + o.pdsbuild = true; +#else + o.pdsbuild = false; + fprintf(stdout, "Warning: You are using the -z option which only works on z/OS.\n"); + +#endif + } else { + o.pdsbuild = false; + } + + o.verbose = options[VERBOSE].doesOccur; + + +#if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN) /* on UNIX, we'll just include the file... */ + if (options[BLDOPT].doesOccur) { + o.options = options[BLDOPT].value; + } else { + o.options = nullptr; + } +#endif + if(options[COPYRIGHT].doesOccur) { + o.comment = U_COPYRIGHT_STRING; + } else if (options[COMMENT].doesOccur) { + o.comment = options[COMMENT].value; + } + + if( options[DESTDIR].doesOccur ) { + o.targetDir = options[DESTDIR].value; + } else { + o.targetDir = "."; /* cwd */ + } + + o.rebuild = options[REBUILD].doesOccur; + + if( options[TEMPDIR].doesOccur ) { + o.tmpDir = options[TEMPDIR].value; + } else { + o.tmpDir = o.targetDir; + } + + if( options[INSTALL].doesOccur ) { + o.install = options[INSTALL].value; + } else { + o.install = nullptr; + } + + if( options[SOURCEDIR].doesOccur ) { + o.srcDir = options[SOURCEDIR].value; + } else { + o.srcDir = "."; + } + + if( options[ENTRYPOINT].doesOccur ) { + o.entryName = options[ENTRYPOINT].value; + } else { + o.entryName = o.cShortName; + } + + o.withoutAssembly = false; + if (options[WITHOUT_ASSEMBLY].doesOccur) { +#ifndef BUILD_DATA_WITHOUT_ASSEMBLY + fprintf(stdout, "Warning: You are using the option to build without assembly code which is not supported on this platform.\n"); + fprintf(stdout, "Warning: This option will be ignored.\n"); +#else + o.withoutAssembly = true; +#endif + } + + if (options[WIN_DYNAMICBASE].doesOccur) { + fprintf(stdout, "Note: Ignoring option -b (windows-dynamicbase).\n"); + } + + /* OK options are set up. Now the file lists. */ + tail = nullptr; + for( n=1; n<argc; n++) { + o.fileListFiles = pkg_appendToList(o.fileListFiles, &tail, uprv_strdup(argv[n])); + } + + /* load the files */ + loadLists(&o, &status); + if( U_FAILURE(status) ) { + fprintf(stderr, "error loading input file lists: %s\n", u_errorName(status)); + return 2; + } + + result = pkg_executeOptions(&o); + + if (pkgDataFlags != nullptr) { + for (n = 0; n < PKGDATA_FLAGS_SIZE; n++) { + if (pkgDataFlags[n] != nullptr) { + uprv_free(pkgDataFlags[n]); + } + } + uprv_free(pkgDataFlags); + } + + if (o.cShortName != nullptr) { + uprv_free((char *)o.cShortName); + } + if (o.fileListFiles != nullptr) { + pkg_deleteList(o.fileListFiles); + } + if (o.filePaths != nullptr) { + pkg_deleteList(o.filePaths); + } + if (o.files != nullptr) { + pkg_deleteList(o.files); + } + return result; +} + +static int runCommand(const char* command, UBool specialHandling) { + char *cmd = nullptr; + char cmdBuffer[SMALL_BUFFER_MAX_SIZE]; + int32_t len = static_cast<int32_t>(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, + 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;i<PKGDATA_FLAGS_SIZE;i++) { + fprintf(stdout, " [%d] %s: %s\n", i, FLAG_NAMES[i], pkgDataFlags[i]); + } + fprintf(stdout, "\n"); + } +#if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN) + } while (status == U_BUFFER_OVERFLOW_ERROR); +#endif + + return result; +} + + +/* + * Given the base libName and version numbers, generate the library file names and store it in libFileNames. + * Depending on the configuration, the library name may either end with version number or shared object suffix. + */ +static void createFileNames(UPKGOptions *o, const char mode, const char *version_major, const char *version, const char *libName, UBool reverseExt, UBool noVersion) { + const char* FILE_EXTENSION_SEP = uprv_strlen(pkgDataFlags[SO_EXT]) == 0 ? "" : "."; + const char* FILE_SUFFIX = pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : ""; + +#if U_PLATFORM == U_PF_MINGW + /* MinGW does not need the library prefix when building in dll mode. */ + if (IN_DLL_MODE(mode)) { + snprintf(libFileNames[LIB_FILE], sizeof(libFileNames[LIB_FILE]), "%s", libName); + } else { + snprintf(libFileNames[LIB_FILE], sizeof(libFileNames[LIB_FILE]), "%s%s%s", + (strstr(libName, "icudt") ? "lib" : ""), + pkgDataFlags[LIBPREFIX], + libName); + } +#else + snprintf(libFileNames[LIB_FILE], sizeof(libFileNames[LIB_FILE]), "%s%s", + pkgDataFlags[LIBPREFIX], + libName); +#endif + + if(o->verbose) { + 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<int32_t>(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<int32_t>(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<int32_t>(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<int32_t>(uprv_strlen(targetDir) + uprv_strlen(libFileNames[LIB_FILE_CYGWIN_VERSION])); +#elif U_PLATFORM == U_PF_MINGW + length += static_cast<int32_t>(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<int32_t>(uprv_strlen(pkgDataFlags[COMPILER]) + uprv_strlen(pkgDataFlags[LIBFLAGS]) + + uprv_strlen(tempObjectFile) + uprv_strlen(gencFilePath) + BUFFER_PADDING_SIZE); + + LocalMemory<char> 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<int32_t>(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<int32_t>(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<int32_t>(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<int32_t>(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<int32_t>(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<int32_t>(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; + 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/intl/icu/source/tools/pkgdata/pkgdata.vcxproj b/intl/icu/source/tools/pkgdata/pkgdata.vcxproj new file mode 100644 index 0000000000..0975456bda --- /dev/null +++ b/intl/icu/source/tools/pkgdata/pkgdata.vcxproj @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup Label="Globals"> + <ProjectGuid>{4C8454FE-81D3-4CA3-9927-29BA96F03DAC}</ProjectGuid> + </PropertyGroup> + <PropertyGroup Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseOfMfc>false</UseOfMfc> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <!-- The following import will include the 'default' configuration options for VS projects. --> + <Import Project="..\..\allinone\Build.Windows.ProjectConfiguration.props" /> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> + <OutDir>.\$(Platform)\$(Configuration)\</OutDir> + <IntDir>.\$(Platform)\$(Configuration)\</IntDir> + <!-- The ICU projects use "Win32" to mean "x86", so we need to special case it. --> + <OutDir Condition="'$(Platform)'=='Win32'">.\x86\$(Configuration)\</OutDir> + <IntDir Condition="'$(Platform)'=='Win32'">.\x86\$(Configuration)\</IntDir> + <!-- Disable Incremental Linking for Release builds as it prevents Link-time Code Generation --> + <LinkIncremental Condition="'$(Configuration)'=='Debug'">true</LinkIncremental> + <LinkIncremental Condition="'$(Configuration)'=='Release'">false</LinkIncremental> + </PropertyGroup> + <!-- Options that are common to *all* configurations --> + <ItemDefinitionGroup> + <Midl> + <TypeLibraryName>$(OutDir)/pkgdata.tlb</TypeLibraryName> + </Midl> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <CompileAs>Default</CompileAs> + <DisableLanguageExtensions>true</DisableLanguageExtensions> + <AdditionalIncludeDirectories>../../../include;../../common;../toolutil;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PrecompiledHeaderOutputFile>$(OutDir)/pkgdata.pch</PrecompiledHeaderOutputFile> + <AssemblerListingLocation>$(OutDir)/</AssemblerListingLocation> + <ObjectFileName>$(OutDir)/</ObjectFileName> + <ProgramDataBaseFileName>$(OutDir)/pkgdata.pdb</ProgramDataBaseFileName> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <OutputFile>$(OutDir)/pkgdata.exe</OutputFile> + <AdditionalLibraryDirectories>..\..\..\$(IcuLibOutputDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + </Link> + <CustomBuildStep> + <Command>copy "$(TargetPath)" ..\..\..\$(IcuBinOutputDir)</Command> + <Outputs>..\..\..\$(IcuBinOutputDir)\$(TargetFileName);%(Outputs)</Outputs> + </CustomBuildStep> + </ItemDefinitionGroup> + <!-- Options that are common to all 'Debug' project configurations --> + <ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'"> + <ClCompile> + <BrowseInformation>true</BrowseInformation> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + </ClCompile> + <Link> + <AdditionalDependencies>icuucd.lib;icutud.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <!-- Options that are common to all 'Release' project configurations --> + <ItemDefinitionGroup Condition="'$(Configuration)'=='Release'"> + <ClCompile> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <FunctionLevelLinking>true</FunctionLevelLinking> + </ClCompile> + <Link> + <AdditionalDependencies>icuuc.lib;icutu.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="pkgdata.cpp" /> + <ClCompile Include="pkgtypes.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="pkgtypes.h" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/intl/icu/source/tools/pkgdata/pkgdata.vcxproj.filters b/intl/icu/source/tools/pkgdata/pkgdata.vcxproj.filters new file mode 100644 index 0000000000..dc530aba11 --- /dev/null +++ b/intl/icu/source/tools/pkgdata/pkgdata.vcxproj.filters @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{73901add-40cd-4d05-a0ba-d336fa136062}</UniqueIdentifier> + <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{0dcaab2b-a92a-430e-8185-de2a2ababd2a}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{4a7309b1-40ce-4bb5-b80d-2cc01b68e8d0}</UniqueIdentifier> + <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="pkgdata.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="pkgtypes.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="pkgtypes.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/intl/icu/source/tools/pkgdata/pkgtypes.c b/intl/icu/source/tools/pkgdata/pkgtypes.c new file mode 100644 index 0000000000..26bd945df7 --- /dev/null +++ b/intl/icu/source/tools/pkgdata/pkgtypes.c @@ -0,0 +1,303 @@ +// © 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.c +* encoding: ANSI X3.4 (1968) +* tab size: 8 (not used) +* indentation:4 +* +* created on: 2000may16 +* created by: Steven \u24C7 Loomis +* +* common types for pkgdata +*/ + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include "unicode/utypes.h" +#include "unicode/putil.h" +#include "cmemory.h" +#include "cstring.h" +#include "pkgtypes.h" +#include "putilimp.h" + +const char *pkg_writeCharListWrap(FileStream *s, CharList *l, const char *delim, const char *brk, int32_t quote) +{ + int32_t ln = 0; + char buffer[1024]; + while(l != NULL) + { + if(l->str) + { + uprv_strncpy(buffer, l->str, 1020); + buffer[1019]=0; + + if(quote < 0) { /* remove quotes */ + if(buffer[uprv_strlen(buffer)-1] == '"') { + buffer[uprv_strlen(buffer)-1] = '\0'; + } + if(buffer[0] == '"') { + uprv_strcpy(buffer, buffer+1); + } + } else if(quote > 0) { /* add quotes */ + if(l->str[0] != '"') { + uprv_strcpy(buffer, "\""); + uprv_strncat(buffer, l->str,1020); + } + if(l->str[uprv_strlen(l->str)-1] != '"') { + uprv_strcat(buffer, "\""); + } + } + T_FileStream_write(s, buffer, (int32_t)uprv_strlen(buffer)); + + ln += (int32_t)uprv_strlen(l->str); + } + + if(l->next && delim) + { + if(ln > 60 && brk) { + ln = 0; + T_FileStream_write(s, brk, (int32_t)uprv_strlen(brk)); + } + T_FileStream_write(s, delim, (int32_t)uprv_strlen(delim)); + } + l = l->next; + } + return NULL; +} + + +const char *pkg_writeCharList(FileStream *s, CharList *l, const char *delim, int32_t quote) +{ + char buffer[1024]; + while(l != NULL) + { + if(l->str) + { + uprv_strncpy(buffer, l->str, 1023); + buffer[1023]=0; + if(uprv_strlen(l->str) >= 1023) + { + fprintf(stderr, "%s:%d: Internal error, line too long (greater than 1023 chars)\n", + __FILE__, __LINE__); + exit(0); + } + if(quote < 0) { /* remove quotes */ + if(buffer[uprv_strlen(buffer)-1] == '"') { + buffer[uprv_strlen(buffer)-1] = '\0'; + } + if(buffer[0] == '"') { + uprv_strcpy(buffer, buffer+1); + } + } else if(quote > 0) { /* add quotes */ + if(l->str[0] != '"') { + uprv_strcpy(buffer, "\""); + uprv_strcat(buffer, l->str); + } + if(l->str[uprv_strlen(l->str)-1] != '"') { + uprv_strcat(buffer, "\""); + } + } + T_FileStream_write(s, buffer, (int32_t)uprv_strlen(buffer)); + } + + if(l->next && delim) + { + T_FileStream_write(s, delim, (int32_t)uprv_strlen(delim)); + } + l = l->next; + } + return NULL; +} + + +/* + * Count items . 0 if null + */ +uint32_t pkg_countCharList(CharList *l) +{ + uint32_t c = 0; + while(l != NULL) + { + c++; + l = l->next; + } + + return c; +} + +/* + * Prepend string to CharList + */ +CharList *pkg_prependToList(CharList *l, const char *str) +{ + CharList *newList; + newList = uprv_malloc(sizeof(CharList)); + + /* test for NULL */ + if(newList == NULL) { + return NULL; + } + + newList->str = str; + newList->next = l; + return newList; +} + +/* + * append string to CharList. *end or even end can be null if you don't + * know it.[slow] + * Str is adopted! + */ +CharList *pkg_appendToList(CharList *l, CharList** end, const char *str) +{ + CharList *endptr = NULL, *tmp; + + if(end == NULL) + { + end = &endptr; + } + + /* FIND the end */ + if((*end == NULL) && (l != NULL)) + { + tmp = l; + while(tmp->next) + { + tmp = tmp->next; + } + + *end = tmp; + } + + /* Create a new empty list and append it */ + if(l == NULL) + { + l = pkg_prependToList(NULL, str); + } + else + { + (*end)->next = pkg_prependToList(NULL, str); + } + + /* Move the end pointer. */ + if(*end) + { + (*end) = (*end)->next; + } + else + { + *end = l; + } + + return l; +} + +char * convertToNativePathSeparators(char *path) { +#if defined(U_MAKE_IS_NMAKE) + char *itr; + while ((itr = uprv_strchr(path, U_FILE_ALT_SEP_CHAR))) { + *itr = U_FILE_SEP_CHAR; + } +#endif + return path; +} + +CharList *pkg_appendUniqueDirToList(CharList *l, CharList** end, const char *strAlias) { + char aBuf[1024]; + char *rPtr; + rPtr = uprv_strrchr(strAlias, U_FILE_SEP_CHAR); +#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR) + { + char *aPtr = uprv_strrchr(strAlias, U_FILE_ALT_SEP_CHAR); + if(!rPtr || /* regular char wasn't found or.. */ + (aPtr && (aPtr > rPtr))) + { /* alt ptr exists and is to the right of r ptr */ + rPtr = aPtr; /* may copy NULL which is OK */ + } + } +#endif + if(!rPtr) { + return l; /* no dir path */ + } + if((rPtr-strAlias) >= UPRV_LENGTHOF(aBuf)) { + fprintf(stderr, "## ERR: Path too long [%d chars]: %s\n", (int)sizeof(aBuf), strAlias); + return l; + } + strncpy(aBuf, strAlias,(rPtr-strAlias)); + aBuf[rPtr-strAlias]=0; /* no trailing slash */ + convertToNativePathSeparators(aBuf); + + if(!pkg_listContains(l, aBuf)) { + return pkg_appendToList(l, end, uprv_strdup(aBuf)); + } else { + return l; /* already found */ + } +} + +#if 0 +static CharList * +pkg_appendFromStrings(CharList *l, CharList** end, const char *s, int32_t len) +{ + CharList *endptr = NULL; + const char *p; + char *t; + const char *targ; + if(end == NULL) { + end = &endptr; + } + + if(len==-1) { + len = uprv_strlen(s); + } + targ = s+len; + + while(*s && s<targ) { + while(s<targ&&isspace(*s)) s++; + for(p=s;s<targ&&!isspace(*p);p++); + if(p!=s) { + t = uprv_malloc(p-s+1); + uprv_strncpy(t,s,p-s); + t[p-s]=0; + l=pkg_appendToList(l,end,t); + fprintf(stderr, " P %s\n", t); + } + s=p; + } + + return l; +} +#endif + + +/* + * Delete list + */ +void pkg_deleteList(CharList *l) +{ + CharList *tmp; + while(l != NULL) + { + uprv_free((void*)l->str); + tmp = l; + l = l->next; + uprv_free(tmp); + } +} + +UBool pkg_listContains(CharList *l, const char *str) +{ + for(;l;l=l->next){ + if(!uprv_strcmp(l->str, str)) { + return true; + } + } + + return false; +} diff --git a/intl/icu/source/tools/pkgdata/pkgtypes.h b/intl/icu/source/tools/pkgdata/pkgtypes.h new file mode 100644 index 0000000000..51c11e0a14 --- /dev/null +++ b/intl/icu/source/tools/pkgdata/pkgtypes.h @@ -0,0 +1,172 @@ +// © 2016 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html +/************************************************************************** +* +* Copyright (C) 2000-2012, International Business Machines +* Corporation and others. All Rights Reserved. +* +*************************************************************************** +* file name: pkgdata.c +* encoding: ANSI X3.4 (1968) +* tab size: 8 (not used) +* indentation:4 +* +* created on: 2000may16 +* created by: Steven \u24C7 Loomis +* +* common types for pkgdata +*/ + +#ifndef _PKGTYPES +#define _PKGTYPES + +/* headers */ +#include "unicode/utypes.h" +#include "filestrm.h" + +/* linked list */ +struct _CharList; + +typedef struct _CharList +{ + const char *str; + struct _CharList *next; +} CharList; + + + +/* + * write CharList 'l' into stream 's' using delimiter 'delim' (delim can be nullptr). quoted: -1 remove, 0 as is, 1 add quotes + */ +const char *pkg_writeCharList(FileStream *s, CharList *l, const char *delim, int32_t quoted); + +/* + * Same, but use line breaks. quoted: -1 remove, 0 as is, 1 add quotes + */ +const char *pkg_writeCharListWrap(FileStream *s, CharList *l, const char *delim, const char *brk, int32_t quoted); + + +/* + * Count items . 0 if null + */ +uint32_t pkg_countCharList(CharList *l); + +/* + * Prepend string to CharList. Str is adopted! + */ +CharList *pkg_prependToList(CharList *l, const char *str); + +/* + * append string to CharList. *end or even end can be null if you don't + * know it.[slow] + * Str is adopted! + */ +CharList *pkg_appendToList(CharList *l, CharList** end, const char *str); + +/* + * strAlias is an alias to a full or relative path to a FILE. This function + * will search strAlias for the directory name (with strrchr). Then, it will + * determine if that directory is already in list l. If not, it will add it + * with strdup(strAlias). + * @param l list to append to , or nullptr + * @param end end pointer-to-pointer. Can point to null, or be null. + * @param strAlias alias to full path string + * @return new list + */ +CharList *pkg_appendUniqueDirToList(CharList *l, CharList** end, const char *strAlias); + +/* + * does list contain string? Returns: t/f + */ +UBool pkg_listContains(CharList *l, const char *str); + +/* + * Delete list + */ +void pkg_deleteList(CharList *l); + +/* + * Mode package function + */ +struct UPKGOptions_; +typedef void (UPKGMODE)(struct UPKGOptions_ *, FileStream *s, UErrorCode *status); + +/* + * Static mode - write the readme file + * @param opt UPKGOptions + * @param libName Name of the .lib, etc file + * @param status ICU error code + */ +void pkg_sttc_writeReadme(struct UPKGOptions_ *opt, const char *libName, UErrorCode *status); + +/* + * Options to be passed throughout the program + */ + +typedef struct UPKGOptions_ +{ + CharList *fileListFiles; /* list of files containing files for inclusion in the package */ + CharList *filePaths; /* All the files, with long paths */ + CharList *files; /* All the files */ + CharList *outFiles; /* output files [full paths] */ + + const char *shortName; /* name of what we're building */ + const char *cShortName; /* name of what we're building as a C identifier */ + const char *entryName; /* special entrypoint name */ + const char *targetDir; /* dir for packaged data to go */ + const char *dataDir; /* parent of dir for package (default: tmpdir) */ + const char *tmpDir; + const char *srcDir; + const char *options; /* Options arg */ + const char *mode; /* Mode of building */ + const char *version; /* Library version */ + const char *comment; /* comment string */ + const char *install; /* Where to install to (nullptr = don't install) */ + const char *icuroot; /* where does ICU lives */ + const char *libName; /* name for library (default: shortName) */ + UBool rebuild; + UBool verbose; + UBool quiet; + UBool withoutAssembly; + UBool pdsbuild; /* for building PDS in z/OS */ +} UPKGOptions; + +char * convertToNativePathSeparators(char *path); + + +/* set up common defines for library naming */ + +#if U_PLATFORM_HAS_WIN32_API +# ifndef UDATA_SO_SUFFIX +# define UDATA_SO_SUFFIX ".dll" +# endif +# define LIB_PREFIX "" +# define LIB_STATIC_PREFIX "" +# define OBJ_SUFFIX ".obj" +# define UDATA_LIB_SUFFIX ".lib" + +#elif U_PLATFORM == U_PF_CYGWIN +# define LIB_PREFIX "cyg" +# define LIB_STATIC_PREFIX "lib" +# define OBJ_SUFFIX ".o" +# define UDATA_LIB_SUFFIX ".a" + +#else /* POSIX? */ +# define LIB_PREFIX "lib" +# define LIB_STATIC_PREFIX "lib" +# define OBJ_SUFFIX ".o" +# define UDATA_LIB_SUFFIX ".a" +#endif + +#define ASM_SUFFIX ".s" + +/* defines for common file names */ +#define UDATA_CMN_PREFIX "" +#define UDATA_CMN_SUFFIX ".dat" +#define UDATA_CMN_INTERMEDIATE_SUFFIX "_dat" + +#define ICUDATA_RES_FILE "icudata.res" + +#define PKGDATA_DERIVED_PATH '\t' + +#endif diff --git a/intl/icu/source/tools/pkgdata/sources.txt b/intl/icu/source/tools/pkgdata/sources.txt new file mode 100644 index 0000000000..8a5b202fa9 --- /dev/null +++ b/intl/icu/source/tools/pkgdata/sources.txt @@ -0,0 +1,2 @@ +pkgdata.cpp +pkgtypes.c |