#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__)
#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"
#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
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 = NULL, 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_getOptionsFromICUConfig(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,
UWP_BUILD,
UWP_ARM_BUILD
};
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[]={
UOPTION_DEF( "name", 'p', UOPT_REQUIRES_ARG),
UOPTION_DEF( "bldopt", 'O', UOPT_REQUIRES_ARG),
UOPTION_DEF( "mode", 'm', UOPT_REQUIRES_ARG),
UOPTION_HELP_H,
UOPTION_HELP_QUESTION_MARK,
UOPTION_VERBOSE,
UOPTION_COPYRIGHT,
UOPTION_DEF( "comment", 'C', UOPT_REQUIRES_ARG),
UOPTION_DESTDIR,
UOPTION_DEF( "rebuild", 'F', UOPT_NO_ARG),
UOPTION_DEF( "tempdir", 'T', UOPT_REQUIRES_ARG),
UOPTION_DEF( "install", 'I', UOPT_REQUIRES_ARG),
UOPTION_SOURCEDIR ,
UOPTION_DEF( "entrypoint", 'e', UOPT_REQUIRES_ARG),
UOPTION_DEF( "revision", 'r', UOPT_REQUIRES_ARG),
UOPTION_DEF( "force-prefix", 'f', UOPT_NO_ARG),
UOPTION_DEF( "libname", 'L', UOPT_REQUIRES_ARG),
UOPTION_DEF( "quiet", 'q', UOPT_NO_ARG),
UOPTION_DEF( "without-assembly", 'w', UOPT_NO_ARG),
UOPTION_DEF("zos-pds-build", 'z', UOPT_NO_ARG),
UOPTION_DEF("windows-uwp-build", 'u', UOPT_NO_ARG),
UOPTION_DEF("windows-uwp-arm-build", 'a', UOPT_NO_ARG)
};
enum {
GENCCODE_ASSEMBLY_TYPE,
SO_EXT,
SOBJ_EXT,
A_EXT,
LIBPREFIX,
LIB_EXT_ORDER,
COMPILER,
LIBFLAGS,
GENLIB,
LDICUDTFLAGS,
LD_SONAME,
RPATH_FLAGS,
BIR_FLAGS,
AR,
ARFLAGS,
RANLIB,
INSTALL_CMD,
PKGDATA_FLAGS_SIZE
};
static 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 = NULL;
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)",
"Set DLL machine type for UWP to target windows ARM (Windows UWP build only)"
};
const char *progname = "PKGDATA";
int
main(int argc, char* argv[]) {
int result = 0;
UPKGOptions o;
CharList *tail;
UBool needsHelp = FALSE;
UErrorCode status = U_ZERO_ERROR;
uint32_t i;
int32_t n;
U_MAIN_INIT_ARGS(argc, argv);
progname = argv[0];
options[MODE].value = "common";
argc=u_parseArgs(argc, argv, UPRV_LENGTHOF(options), options);
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_getOptionsFromICUConfig(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)
{
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;
}
}
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;
}
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) {
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)
if (options[BLDOPT].doesOccur) {
o.options = options[BLDOPT].value;
} else {
o.options = NULL;
}
#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 = ".";
}
o.rebuild = options[REBUILD].doesOccur;
if( options[TEMPDIR].doesOccur ) {
o.tmpDir = options[TEMPDIR].value;
} else {
o.tmpDir = o.targetDir;
}
if( options[INSTALL].doesOccur ) {
o.install = options[INSTALL].value;
} else {
o.install = NULL;
}
if( options[SOURCEDIR].doesOccur ) {
o.srcDir = options[SOURCEDIR].value;
} else {
o.srcDir = ".";
}
if( options[ENTRYPOINT].doesOccur ) {
o.entryName = options[ENTRYPOINT].value;
} else {
o.entryName = o.cShortName;
}
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
}
tail = NULL;
for( n=1; n<argc; n++) {
o.fileListFiles = pkg_appendToList(o.fileListFiles, &tail, uprv_strdup(argv[n]));
}
loadLists(&o, &status);
if( U_FAILURE(status) ) {
fprintf(stderr, "error loading input file lists: %s\n", u_errorName(status));
return 2;
}
result = pkg_executeOptions(&o);
if (pkgDataFlags != NULL) {
for (n = 0; n < PKGDATA_FLAGS_SIZE; n++) {
if (pkgDataFlags[n] != NULL) {
uprv_free(pkgDataFlags[n]);
}
}
uprv_free(pkgDataFlags);
}
if (o.cShortName != NULL) {
uprv_free((char *)o.cShortName);
}
if (o.fileListFiles != NULL) {
pkg_deleteList(o.fileListFiles);
}
if (o.filePaths != NULL) {
pkg_deleteList(o.filePaths);
}
if (o.files != NULL) {
pkg_deleteList(o.files);
}
return result;
}
static int runCommand(const char* command, UBool specialHandling) {
char *cmd = NULL;
char cmdBuffer[SMALL_BUFFER_MAX_SIZE];
int32_t len = strlen(command);
if (len == 0) {
return 0;
}
if (!specialHandling) {
#if defined(USING_CYGWIN) || U_PLATFORM == U_PF_MINGW || U_PLATFORM == U_PF_OS400
if ((len + BUFFER_PADDING_SIZE) >= SMALL_BUFFER_MAX_SIZE) {
cmd = (char *)uprv_malloc(len + BUFFER_PADDING_SIZE);
} else {
cmd = cmdBuffer;
}
#if defined(USING_CYGWIN) || U_PLATFORM == U_PF_MINGW
sprintf(cmd, "bash -c \"%s\"", command);
#elif U_PLATFORM == U_PF_OS400
sprintf(cmd, "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);
}
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)) {
if (o->install != NULL) {
uprv_strcpy(targetDir, o->install);
if (o->shortName != NULL) {
uprv_strcat(targetDir, PKGDATA_FILE_SEP_STRING);
uprv_strcat(targetDir, o->shortName);
}
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 {
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, NULL, 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);
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 != NULL) {
result = pkg_installCommonMode(o->install, targetFileNamePath);
}
return result;
} else {
char gencFilePath[SMALL_BUFFER_MAX_SIZE] = "";
char version_major[10] = "";
UBool reverseExt = FALSE;
#if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN)
if (o->version != NULL) {
for (uint32_t i = 0;i < sizeof(version_major);i++) {
if (o->version[i] == '.') {
version_major[i] = 0;
break;
}
version_major[i] = o->version[i];
}
} 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
if (pkgDataFlags[LIB_EXT_ORDER][uprv_strlen(pkgDataFlags[LIB_EXT_ORDER])-1] == pkgDataFlags[SO_EXT][uprv_strlen(pkgDataFlags[SO_EXT])-1]) {
reverseExt = TRUE;
}
#endif
createFileNames(o, mode, version_major, o->version == NULL ? "" : o->version, o->libName, reverseExt, noVersion);
if ((o->version!=NULL || IN_STATIC_MODE(mode)) && o->rebuild == FALSE && o->pdsbuild == FALSE) {
sprintf(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 != NULL) {
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!=NULL)) {
fprintf(stdout, "# Not installing up-to-date library %s into %s\n", checkLibFile, o->install);
}
} else if(o->verbose && (o->install!=NULL)) {
fprintf(stdout, "# Not installing missing %s into %s\n", checkLibFile, o->install);
}
}
if (pkg_checkFlag(o) == NULL) {
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);
}
if (genccodeAssembly &&
(uprv_strlen(genccodeAssembly)>3) &&
checkAssemblyHeaderName(genccodeAssembly+3)) {
writeAssemblyCode(datFileNamePath, o->tmpDir, o->entryName, NULL, gencFilePath);
result = pkg_createWithAssemblyCode(targetDir, mode, gencFilePath);
if (result != 0) {
fprintf(stderr, "Error generating assembly code for data.\n");
return result;
} else if (IN_STATIC_MODE(mode)) {
if(o->install != NULL) {
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
fprintf(stderr, "Error- BUILD_DATA_WITHOUT_ASSEMBLY is not defined. Internal error.\n");
#endif
} else {
#ifdef CAN_WRITE_OBJ_CODE
char optMatchArch[10] = { 0 };
pkg_createOptMatchArch(optMatchArch);
writeObjectCode(datFileNamePath, o->tmpDir, o->entryName, (optMatchArch[0] == 0 ? NULL : optMatchArch), NULL, gencFilePath);
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)) {
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) {
#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
}
#endif
#if !U_PLATFORM_USES_ONLY_WIN32_API
if (o->install != NULL) {
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;
}
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;
pkgDataFlags = (char**)uprv_malloc(sizeof(char*) * PKGDATA_FLAGS_SIZE);
#if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN)
do {
#endif
if (pkgDataFlags != NULL) {
for (int32_t i = 0; i < PKGDATA_FLAGS_SIZE; i++) {
pkgDataFlags[i] = (char*)uprv_malloc(sizeof(char) * currentBufferSize);
if (pkgDataFlags[i] != NULL) {
pkgDataFlags[i][0] = 0;
} else {
fprintf(stderr,"Error allocating memory for pkgDataFlags.\n");
for (int32_t n = i + 1; n < PKGDATA_FLAGS_SIZE; n++) {
pkgDataFlags[n] = NULL;
}
return -1;
}
}
} else {
fprintf(stderr,"Error allocating memory for pkgDataFlags.\n");
return -1;
}
if (o->options == NULL) {
return result;
}
#if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN)
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] = NULL;
}
}
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;
}
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
if (IN_DLL_MODE(mode)) {
sprintf(libFileNames[LIB_FILE], "%s", libName);
} else {
sprintf(libFileNames[LIB_FILE], "%s%s",
pkgDataFlags[LIBPREFIX],
libName);
}
#else
sprintf(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
sprintf(libFileNames[LIB_FILE_MINGW], "lib%s.dll.a", libName);
#elif U_PLATFORM == U_PF_CYGWIN
sprintf(libFileNames[LIB_FILE_CYGWIN], "cyg%s%s%s",
libName,
FILE_EXTENSION_SEP,
pkgDataFlags[SO_EXT]);
sprintf(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)
sprintf(libFileNames[LIB_FILE_VERSION_TMP], "%s%s%s",
libFileNames[LIB_FILE],
FILE_EXTENSION_SEP,
pkgDataFlags[SOBJ_EXT]);
#elif U_PLATFORM == U_PF_OS390
sprintf(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);
sprintf(libFileNames[LIB_FILE_OS390BATCH_VERSION], "%s%s.x",
libFileNames[LIB_FILE],
version);
sprintf(libFileNames[LIB_FILE_OS390BATCH_MAJOR], "%s%s.x",
libFileNames[LIB_FILE],
version_major);
#else
if (noVersion && !reverseExt) {
sprintf(libFileNames[LIB_FILE_VERSION_TMP], "%s%s%s",
libFileNames[LIB_FILE],
FILE_SUFFIX,
pkgDataFlags[SOBJ_EXT]);
} else {
sprintf(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) {
sprintf(libFileNames[LIB_FILE_VERSION_MAJOR], "%s%s%s",
libFileNames[LIB_FILE],
FILE_SUFFIX,
pkgDataFlags[SO_EXT]);
sprintf(libFileNames[LIB_FILE_VERSION], "%s%s%s",
libFileNames[LIB_FILE],
FILE_SUFFIX,
pkgDataFlags[SO_EXT]);
} else {
sprintf(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);
sprintf(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
uprv_strcpy(libFileNames[LIB_FILE_VERSION_TMP], libFileNames[LIB_FILE_VERSION_MAJOR]);
#endif
if(IN_STATIC_MODE(mode)) {
sprintf(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]);
}
}
}
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];
char name2[SMALL_BUFFER_MAX_SIZE];
const char* FILE_EXTENSION_SEP = uprv_strlen(pkgDataFlags[SO_EXT]) == 0 ? "" : ".";
#if !defined(USING_CYGWIN) && U_PLATFORM != U_PF_MINGW
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;
}
sprintf(cmd, "cd %s && %s %s && %s %s %s",
targetDir,
RM_CMD,
libFileNames[LIB_FILE_VERSION_MAJOR],
LN_CMD,
libFileNames[LIB_FILE_VERSION],
libFileNames[LIB_FILE_VERSION_MAJOR]);
result = 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
sprintf(name1, "%s", libFileNames[LIB_FILE_CYGWIN]);
sprintf(name2, "%s", libFileNames[LIB_FILE_CYGWIN_VERSION]);
#elif U_PLATFORM == U_PF_OS390
sprintf(cmd, "%s/%s", targetDir, libFileNames[LIB_FILE_OS390BATCH_VERSION]);
if (T_FileStream_file_exists(cmd)) {
sprintf(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;
}
sprintf(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;
}
}
sprintf(name1, "%s%s%s", libFileNames[LIB_FILE], FILE_EXTENSION_SEP, pkgDataFlags[SO_EXT]);
sprintf(name2, "%s", libFileNames[LIB_FILE_VERSION]);
#else
goto normal_symlink_mode;
#endif
} else {
#if U_PLATFORM != U_PF_CYGWIN
normal_symlink_mode:
#endif
sprintf(name1, "%s%s%s", libFileNames[LIB_FILE], FILE_EXTENSION_SEP, pkgDataFlags[SO_EXT]);
sprintf(name2, "%s", libFileNames[LIB_FILE_VERSION]);
}
sprintf(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];
sprintf(cmd, "cd %s && %s %s %s%s%s",
targetDir,
pkgDataFlags[INSTALL_CMD],
libFileNames[LIB_FILE_VERSION],
installDir, PKGDATA_FILE_SEP_STRING, libFileNames[LIB_FILE_VERSION]
);
result = runCommand(cmd);
if (result != 0) {
fprintf(stderr, "Error installing library. Failed command: %s\n", cmd);
return result;
}
#ifdef CYGWINMSVC
sprintf(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
sprintf(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])) {
sprintf(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
sprintf(cmd, "%s %s %s", pkgDataFlags[INSTALL_CMD], fileName, installDir);
#else
sprintf(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
#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 != NULL) {
for(;;) {
if (T_FileStream_readLine(f, buffer, SMALL_BUFFER_MAX_SIZE) != NULL) {
bufferLength = uprv_strlen(buffer);
if (bufferLength > 0) {
buffer[bufferLength-1] = 0;
}
sprintf(cmd, "%s %s%s%s %s%s%s",
pkgDataFlags[INSTALL_CMD],
srcDir, PKGDATA_FILE_SEP_STRING, buffer,
installDir, PKGDATA_FILE_SEP_STRING, buffer);
result = 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
sprintf(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;
}
static int32_t pkg_archiveLibrary(const char *targetDir, const char *version, UBool reverseExt) {
int32_t result = 0;
char cmd[LARGE_BUFFER_MAX_SIZE];
if (uprv_strcmp(pkgDataFlags[SOBJ_EXT], pkgDataFlags[SO_EXT]) != 0 && uprv_strcmp(pkgDataFlags[A_EXT], pkgDataFlags[SO_EXT]) == 0) {
sprintf(libFileNames[LIB_FILE_VERSION], "%s%s%s.%s",
libFileNames[LIB_FILE],
pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "",
reverseExt ? version : pkgDataFlags[SO_EXT],
reverseExt ? pkgDataFlags[SO_EXT] : version);
sprintf(cmd, "%s %s %s%s %s%s",
pkgDataFlags[AR],
pkgDataFlags[ARFLAGS],
targetDir,
libFileNames[LIB_FILE_VERSION],
targetDir,
libFileNames[LIB_FILE_VERSION_TMP]);
result = runCommand(cmd);
if (result != 0) {
fprintf(stderr, "Error creating archive library. Failed command: %s\n", cmd);
return result;
}
sprintf(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;
}
sprintf(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;
}
static int32_t pkg_generateLibraryFile(const char *targetDir, const char mode, const char *objectFile, char *command, UBool specialHandling) {
int32_t result = 0;
char *cmd = NULL;
UBool freeCmd = FALSE;
int32_t length = 0;
(void)specialHandling;
if (command != NULL) {
cmd = command;
}
if (IN_STATIC_MODE(mode)) {
if (cmd == NULL) {
length = 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)) == NULL) {
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 (cmd == NULL) {
length = 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 += uprv_strlen(targetDir) + uprv_strlen(libFileNames[LIB_FILE_CYGWIN_VERSION]);
#elif U_PLATFORM == U_PF_MINGW
length += uprv_strlen(targetDir) + uprv_strlen(libFileNames[LIB_FILE_MINGW]);
#endif
if ((cmd = (char *)uprv_malloc(sizeof(char) * length)) == NULL) {
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]);
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] = "";
char *cmd;
int32_t result = 0;
int32_t length = 0;
uprv_strcpy(tempObjectFile, gencFilePath);
tempObjectFile[uprv_strlen(tempObjectFile)-1] = 'o';
length = uprv_strlen(pkgDataFlags[COMPILER]) + uprv_strlen(pkgDataFlags[LIBFLAGS])
+ uprv_strlen(tempObjectFile) + uprv_strlen(gencFilePath) + BUFFER_PADDING_SIZE;
cmd = (char *)uprv_malloc(sizeof(char) * length);
if (cmd == NULL) {
return -1;
}
sprintf(cmd, "%s %s -o %s %s",
pkgDataFlags[COMPILER],
pkgDataFlags[LIBFLAGS],
tempObjectFile,
gencFilePath);
result = runCommand(cmd);
uprv_free(cmd);
if (result != 0) {
fprintf(stderr, "Error creating with assembly code. Failed command: %s\n", cmd);
return result;
}
return pkg_generateLibraryFile(targetDir, mode, tempObjectFile);
}
#ifdef BUILD_DATA_WITHOUT_ASSEMBLY
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 = NULL;
sprintf(icudtAll, "%s%s%sall.c",
o->tmpDir,
PKGDATA_FILE_SEP_STRING,
libFileNames[LIB_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"))==NULL) {
fprintf(stderr, "Unable to write to icudtall file: %s\n", icudtAll);
return result;
}
#endif
if (list == NULL || listNames == NULL) {
return -1;
}
if ((cmd = (char *)uprv_malloc((listSize + 2) * SMALL_BUFFER_MAX_SIZE)) == NULL) {
fprintf(stderr, "Unable to allocate memory for cmd.\n");
return -1;
} else if ((buffer = (char *)uprv_malloc((listSize + 1) * SMALL_BUFFER_MAX_SIZE)) == NULL) {
fprintf(stderr, "Unable to allocate memory for buffer.\n");
uprv_free(cmd);
return -1;
}
for (int32_t i = 0; i < (listSize + 1); i++) {
const char *file ;
const char *name;
if (i == 0) {
createCommonDataFile(o->tmpDir, o->shortName, o->entryName, NULL, o->srcDir, o->comment, o->fileListFiles->str, 0, TRUE, o->verbose, gencmnFile);
buffer[0] = 0;
#ifdef USE_SINGLE_CCODE_FILE
uprv_strcpy(tempObjectFile, gencmnFile);
tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
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);
pSubstring = uprv_strstr(name, dataDirName);
if (pSubstring != NULL) {
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;
}
}
sprintf(newName, "%s_%s",
DATA_PREFIX[n],
newNameTmp);
sprintf(dataName, "%s_%s",
o->shortName,
DATA_PREFIX[n]);
}
if (newName[0] != 0) {
break;
}
}
if(o->verbose) {
printf("# Generating %s \n", gencmnFile);
}
writeCCode(file, o->tmpDir, dataName[0] != 0 ? dataName : o->shortName, newName[0] != 0 ? newName : NULL, gencmnFile);
#ifdef USE_SINGLE_CCODE_FILE
sprintf(cmd, "#include \"%s\"\n", gencmnFile);
T_FileStream_writeLine(icudtAllFile, cmd);
#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) {
#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 "/DLL /NOENTRY /MANIFEST:NO /implib:"
#ifdef _WIN64
#define LINK_EXTRA_UWP_FLAGS "/NXCOMPAT /DYNAMICBASE /APPCONTAINER "
#else
#define LINK_EXTRA_UWP_FLAGS "/NXCOMPAT /SAFESEH /DYNAMICBASE /APPCONTAINER /MACHINE:X86"
#endif
#define LINK_EXTRA_UWP_FLAGS_ARM "/NXCOMPAT /DYNAMICBASE /APPCONTAINER /MACHINE:ARM"
#define LINK_EXTRA_NO_UWP_FLAGS "/base:0x4ad00000 "
#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
sprintf(staticLibFilePath, "%s%s%s%s%s",
o->targetDir,
PKGDATA_FILE_SEP_STRING,
pkgDataFlags[LIBPREFIX],
o->libName,
LIB_EXT);
#else
sprintf(staticLibFilePath, "%s%s%s%s%s",
o->targetDir,
PKGDATA_FILE_SEP_STRING,
(strstr(o->libName, "icudt") ? "s" : ""),
o->libName,
LIB_EXT);
#endif
sprintf(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)) {
sprintf(resFilePath, "\"%s\"", tmpResFilePath);
}
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 = "";
#ifdef WINDOWS_WITH_MSVC
if (options[UWP_BUILD].doesOccur)
{
if (options[UWP_ARM_BUILD].doesOccur)
{
extraFlags = LINK_EXTRA_UWP_FLAGS_ARM;
}
else
{
extraFlags = LINK_EXTRA_UWP_FLAGS;
}
}
else
{
extraFlags = LINK_EXTRA_NO_UWP_FLAGS;
}
#endif
sprintf(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
char *flag = NULL;
int32_t length = 0;
char tmpbuffer[SMALL_BUFFER_MAX_SIZE];
const char MAP_FILE_EXT[] = ".map";
FileStream *f = NULL;
char mapFile[SMALL_BUFFER_MAX_SIZE] = "";
int32_t start = -1;
uint32_t count = 0;
const char rm_cmd[] = "rm -f all ;";
flag = pkgDataFlags[GENLIB];
if (uprv_strstr(flag, rm_cmd) != NULL) {
char *tmpGenlibFlagBuffer = NULL;
int32_t i, offset;
length = uprv_strlen(flag) + 1;
tmpGenlibFlagBuffer = (char *)uprv_malloc(length);
if (tmpGenlibFlagBuffer == NULL) {
fprintf(stderr,"Unable to allocate buffer of size: %d.\n", length);
return NULL;
}
uprv_strcpy(tmpGenlibFlagBuffer, flag);
offset = uprv_strlen(rm_cmd);
for (i = 0; i < (length - offset); i++) {
flag[i] = tmpGenlibFlagBuffer[offset + i];
}
flag[i] = 0;
uprv_free(tmpGenlibFlagBuffer);
}
flag = pkgDataFlags[BIR_FLAGS];
length = uprv_strlen(pkgDataFlags[BIR_FLAGS]);
for (int32_t i = 0; i < length; i++) {
if (flag[i] == MAP_FILE_EXT[count]) {
if (count == 0) {
start = i;
}
count++;
} else {
count = 0;
}
if (count == uprv_strlen(MAP_FILE_EXT)) {
break;
}
}
if (start >= 0) {
int32_t index = 0;
for (int32_t i = 0;;i++) {
if (i == start) {
for (int32_t n = 0;;n++) {
if (o->shortName[n] == 0) {
break;
}
tmpbuffer[index++] = o->shortName[n];
}
}
tmpbuffer[index++] = flag[i];
if (flag[i] == 0) {
break;
}
}
uprv_memset(flag, 0, length);
uprv_strcpy(flag, tmpbuffer);
uprv_strcpy(mapFile, o->shortName);
uprv_strcat(mapFile, MAP_FILE_EXT);
f = T_FileStream_open(mapFile, "w");
if (f == NULL) {
fprintf(stderr,"Unable to create map file: %s.\n", mapFile);
return NULL;
} else {
sprintf(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
char *flag = NULL;
int32_t length = 0;
flag = pkgDataFlags[GENLIB];
length = uprv_strlen(pkgDataFlags[GENLIB]);
int32_t position = length - 1;
for(;position >= 0;position--) {
if (flag[position] == '=') {
position++;
break;
}
}
uprv_memset(flag + position, 0, length - position);
#elif U_PLATFORM == U_PF_OS400
char *flag = NULL;
int32_t length = 0;
flag = pkgDataFlags[GENLIB];
length = uprv_strlen(pkgDataFlags[GENLIB]);
int32_t position = length - 1;
for(int32_t i = 0; i < length; i++) {
if (flag[i] == '\'') {
flag[i] = '\"';
}
}
#endif
return o;
}
static void loadLists(UPKGOptions *o, UErrorCode *status)
{
CharList *l, *tail = NULL, *tail2 = NULL;
FileStream *in;
char line[16384];
char *linePtr, *lineNext;
const uint32_t lineMax = 16300;
char *tmp;
int32_t tmpLength = 0;
char *s;
int32_t ln=0;
for(l = o->fileListFiles; l; l = l->next) {
if(o->verbose) {
fprintf(stdout, "# pkgdata: Reading %s..\n", l->str);
}
in = T_FileStream_open(l->str, "r");
if(!in) {
fprintf(stderr, "Error opening <%s>.\n", l->str);
*status = U_FILE_ACCESS_ERROR;
return;
}
while(T_FileStream_readLine(in, line, sizeof(line))!=NULL) {
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);
}
linePtr = line;
#if U_PLATFORM != U_PF_OS390
while(isspace(*linePtr)) {
linePtr++;
}
#endif
s=linePtr;
while(*s!=0) {
if(*s=='\r' || *s=='\n') {
*s=0;
break;
}
++s;
}
if((*linePtr == 0) || (*linePtr == '#')) {
continue;
}
lineNext = NULL;
while(linePtr && *linePtr) {
while(*linePtr == ' ') {
linePtr++;
}
if(linePtr[0] == '"')
{
lineNext = uprv_strchr(linePtr+1, '"');
if(lineNext == NULL) {
fprintf(stderr, "%s:%d - missing trailing double quote (\")\n",
l->str, (int)ln);
exit(1);
} else {
lineNext++;
if(*lineNext) {
if(*lineNext != ' ') {
fprintf(stderr, "%s:%d - malformed quoted line at position %d, expected ' ' got '%c'\n",
l->str, (int)ln, (int)(lineNext-line), (*lineNext)?*lineNext:'0');
exit(1);
}
*lineNext = 0;
lineNext++;
}
}
} else {
lineNext = uprv_strchr(linePtr, ' ');
if(lineNext) {
*lineNext = 0;
lineNext++;
}
}
s = (char*)getLongPathname(linePtr);
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);
}
tmpLength = uprv_strlen(o->srcDir) +
uprv_strlen(s) + 5;
if((tmp = (char *)uprv_malloc(tmpLength)) == NULL) {
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;
}
}
T_FileStream_close(in);
}
}
static int32_t pkg_getOptionsFromICUConfig(UBool verbose, UOption *option) {
#if U_HAVE_POPEN
LocalPipeFilePointer p;
size_t n;
static char buf[512] = "";
icu::CharString cmdBuf;
UErrorCode status = U_ZERO_ERROR;
const char cmd[] = "icu-config --incpkgdatafile";
char dirBuf[1024] = "";
findDirname(progname, dirBuf, UPRV_LENGTHOF(dirBuf), &status);
if(U_SUCCESS(status)) {
cmdBuf.append(dirBuf, status);
if (cmdBuf[0] != 0) {
cmdBuf.append( U_FILE_SEP_STRING, status );
}
cmdBuf.append( cmd, status );
if(verbose) {
fprintf(stdout, "# Calling icu-config: %s\n", cmdBuf.data());
}
p.adoptInstead(popen(cmdBuf.data(), "r"));
}
if(p.isNull() || (n = fread(buf, 1, UPRV_LENGTHOF(buf)-1, p.getAlias())) <= 0) {
if(verbose) {
fprintf(stdout, "# Calling icu-config: %s\n", cmd);
}
p.adoptInstead(popen(cmd, "r"));
if(p.isNull() || (n = fread(buf, 1, UPRV_LENGTHOF(buf)-1, p.getAlias())) <= 0) {
fprintf(stderr, "%s: icu-config: No icu-config found. (fix PATH or use -O option)\n", progname);
return -1;
}
}
for (int32_t length = strlen(buf) - 1; length >= 0; length--) {
if (buf[length] == '\n' || buf[length] == ' ') {
buf[length] = 0;
} else {
break;
}
}
if(buf[strlen(buf)-1]=='\n')
{
buf[strlen(buf)-1]=0;
}
if(buf[0] == 0)
{
fprintf(stderr, "%s: icu-config: invalid response from icu-config (fix PATH or use -O option)\n", progname);
return -1;
}
if(verbose) {
fprintf(stdout, "# icu-config said: %s\n", buf);
}
option->value = buf;
option->doesOccur = TRUE;
return 0;
#else
return -1;
#endif
}
#ifdef CAN_WRITE_OBJ_CODE
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 = NULL;
stream = T_FileStream_open(source,"w");
if (stream != NULL) {
T_FileStream_writeLine(stream, code);
T_FileStream_close(stream);
char cmd[LARGE_BUFFER_MAX_SIZE];
sprintf(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