d9124b0ce0
X-SVN-Rev: 25026
1458 lines
45 KiB
C++
1458 lines
45 KiB
C++
/******************************************************************************
|
|
* Copyright (C) 2000-2008, International Business Machines
|
|
* Corporation and others. All Rights Reserved.
|
|
*******************************************************************************
|
|
* file name: pkgdata.c
|
|
* encoding: ANSI X3.4 (1968)
|
|
* tab size: 8 (not used)
|
|
* indentation:4
|
|
*
|
|
* created on: 2000may15
|
|
* created by: Steven \u24C7 Loomis
|
|
*
|
|
* This program packages the ICU data into different forms
|
|
* (DLL, common data, etc.)
|
|
*/
|
|
|
|
/*
|
|
* We define _XOPEN_SOURCE so that we can get popen and pclose.
|
|
*/
|
|
#if !defined(_XOPEN_SOURCE)
|
|
#if __STDC_VERSION__ >= 199901L
|
|
/* It is invalid to compile an XPG3, XPG4, XPG4v2 or XPG5 application using c99 on Solaris */
|
|
#define _XOPEN_SOURCE 600
|
|
#else
|
|
#define _XOPEN_SOURCE 4
|
|
#endif
|
|
#endif
|
|
|
|
#include "unicode/utypes.h"
|
|
#include "unicode/putil.h"
|
|
#include "cmemory.h"
|
|
#include "cstring.h"
|
|
#include "filestrm.h"
|
|
#include "toolutil.h"
|
|
#include "unicode/uclean.h"
|
|
#include "unewdata.h"
|
|
#include "uoptions.h"
|
|
#include "putilimp.h"
|
|
#include "package.h"
|
|
#include "pkg_icu.h"
|
|
#include "pkg_genc.h"
|
|
#include "pkg_gencmn.h"
|
|
|
|
|
|
#if U_HAVE_POPEN
|
|
# include <unistd.h>
|
|
#endif
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
U_CDECL_BEGIN
|
|
#include "pkgtypes.h"
|
|
#include "makefile.h"
|
|
U_CDECL_END
|
|
|
|
#define LARGE_BUFFER_MAX_SIZE 2048
|
|
#define SMALL_BUFFER_MAX_SIZE 512
|
|
|
|
static void loadLists(UPKGOptions *o, UErrorCode *status);
|
|
|
|
static int32_t pkg_executeOptions(UPKGOptions *o);
|
|
|
|
#ifdef U_WINDOWS
|
|
static int32_t pkg_createWindowsDLL(const char mode, const char *gencFilePath, UPKGOptions *o);
|
|
#endif
|
|
static int32_t pkg_createSymLinks(const char *targetDir);
|
|
static int32_t pkg_installLibrary(const char *installDir, const char *dir);
|
|
static int32_t pkg_createWithoutAssemblyCode(UPKGOptions *o, const char *targetDir, const char mode);
|
|
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);
|
|
static int32_t pkg_archiveLibrary(const char *targetDir, const char *version, UBool reverseExt);
|
|
static void createFileNames(const char *version_major, const char *version, const char *libName, const UBool reverseExt);
|
|
|
|
static int32_t pkg_getOptionsFromICUConfig(UOption *option);
|
|
/* always have this fcn, just might not do anything */
|
|
static void fillInMakefileFromICUConfig(UOption *option);
|
|
|
|
/* This sets the modes that are available */
|
|
static struct
|
|
{
|
|
const char *name, *alt_name;
|
|
UPKGMODE *fcn;
|
|
const char *desc;
|
|
} modes[] =
|
|
{
|
|
{ "files", 0, pkg_mode_files, "Uses raw data files (no effect). Installation copies all files to the target location." },
|
|
#ifdef U_MAKE_IS_NMAKE
|
|
{ "dll", "library", pkg_mode_windows, "Generates one common data file and one shared library, <package>.dll"},
|
|
{ "common", "archive", pkg_mode_windows, "Generates just the common file, <package>.dat"},
|
|
{ "static", "static", pkg_mode_windows, "Generates one statically linked library, " LIB_PREFIX "<package>" UDATA_LIB_SUFFIX }
|
|
#else /*#ifdef U_MAKE_IS_NMAKE*/
|
|
#ifdef UDATA_SO_SUFFIX
|
|
{ "dll", "library", pkg_mode_dll, "Generates one shared library, <package>" UDATA_SO_SUFFIX },
|
|
#endif
|
|
{ "common", "archive", pkg_mode_common, "Generates one common data file, <package>.dat" },
|
|
{ "static", "static", pkg_mode_static, "Generates one statically linked library, " LIB_PREFIX "<package>" UDATA_LIB_SUFFIX }
|
|
#endif /*#ifdef U_MAKE_IS_NMAKE*/
|
|
};
|
|
|
|
enum {
|
|
NAME,
|
|
BLDOPT,
|
|
MODE,
|
|
HELP,
|
|
HELP_QUESTION_MARK,
|
|
VERBOSE,
|
|
COPYRIGHT,
|
|
COMMENT,
|
|
DESTDIR,
|
|
CLEAN,
|
|
NOOUTPUT,
|
|
REBUILD,
|
|
TEMPDIR,
|
|
INSTALL,
|
|
SOURCEDIR,
|
|
ENTRYPOINT,
|
|
REVISION,
|
|
FORCE_PREFIX,
|
|
LIBNAME,
|
|
QUIET
|
|
};
|
|
|
|
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 */
|
|
/*09*/ UOPTION_DEF( "clean", 'k', UOPT_NO_ARG),
|
|
/*10*/ UOPTION_DEF( "nooutput",'n', UOPT_NO_ARG),
|
|
/*11*/ UOPTION_DEF( "rebuild", 'F', UOPT_NO_ARG),
|
|
/*12*/ UOPTION_DEF( "tempdir", 'T', UOPT_REQUIRES_ARG),
|
|
/*13*/ UOPTION_DEF( "install", 'I', UOPT_REQUIRES_ARG),
|
|
/*14*/ UOPTION_SOURCEDIR ,
|
|
/*15*/ UOPTION_DEF( "entrypoint", 'e', UOPT_REQUIRES_ARG),
|
|
/*16*/ UOPTION_DEF( "revision", 'r', UOPT_REQUIRES_ARG),
|
|
/*17*/ UOPTION_DEF( "force-prefix", 'f', UOPT_NO_ARG),
|
|
/*18*/ UOPTION_DEF( "libname", 'L', UOPT_REQUIRES_ARG),
|
|
/*19*/ UOPTION_DEF( "quiet", 'q', UOPT_NO_ARG)
|
|
};
|
|
|
|
enum {
|
|
GENCCODE_ASSEMBLY_TYPE,
|
|
SO_EXT,
|
|
SOBJ_EXT,
|
|
A_EXT,
|
|
LIBPREFIX,
|
|
LIB_EXT_ORDER,
|
|
COMPILER,
|
|
LIBFLAGS,
|
|
GENLIB,
|
|
LDICUDTFLAGS,
|
|
LD_SONAME,
|
|
RPATH_FLAGS,
|
|
BIR_FLAGS,
|
|
AR,
|
|
ARFLAGS,
|
|
RANLIB,
|
|
INSTALL_CMD,
|
|
PKGDATA_FLAGS_SIZE
|
|
};
|
|
static char pkgDataFlags[PKGDATA_FLAGS_SIZE][SMALL_BUFFER_MAX_SIZE];
|
|
|
|
enum {
|
|
LIB_FILE,
|
|
LIB_FILE_VERSION_MAJOR,
|
|
LIB_FILE_VERSION,
|
|
LIB_FILE_VERSION_TMP,
|
|
#ifdef U_CYGWIN
|
|
LIB_FILE_CYGWIN,
|
|
#endif
|
|
LIB_FILENAMES_SIZE
|
|
};
|
|
static char libFileNames[LIB_FILENAMES_SIZE][256];
|
|
|
|
static int32_t pkg_readInFlags(const char* fileName);
|
|
|
|
static void pkg_checkFlag(UPKGOptions *o);
|
|
|
|
const char options_help[][320]={
|
|
"Set the data name",
|
|
#ifdef U_MAKE_IS_NMAKE
|
|
"The directory where the ICU is located (e.g. <ICUROOT> which contains the bin directory)",
|
|
#else
|
|
"Specify options for the builder.",
|
|
#endif
|
|
"Specify the mode of building (see below; default: common)",
|
|
"This usage text",
|
|
"This usage text",
|
|
"Make the output verbose",
|
|
"Use the standard ICU copyright",
|
|
"Use a custom comment (instead of the copyright)",
|
|
"Specify the destination directory for files",
|
|
"Clean out generated & temporary files",
|
|
"Suppress output of data, just list files to be created",
|
|
"Force rebuilding of all data",
|
|
"Specify temporary dir (default: output dir)",
|
|
"Install the data (specify target)",
|
|
"Specify a custom source directory",
|
|
"Specify a custom entrypoint name (default: short name)",
|
|
"Specify a version when packaging in DLL or static mode",
|
|
"Add package to all file names if not present",
|
|
"Library name to build (if different than package name)",
|
|
"Quite mode. (e.g. Do not output a readme file for static libraries)"
|
|
};
|
|
|
|
const char *progname = "PKGDATA";
|
|
|
|
int
|
|
main(int argc, char* argv[]) {
|
|
int result = 0;
|
|
/* FileStream *out; */
|
|
UPKGOptions o;
|
|
CharList *tail;
|
|
UBool needsHelp = FALSE;
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
/* char tmp[1024]; */
|
|
int32_t i;
|
|
|
|
U_MAIN_INIT_ARGS(argc, argv);
|
|
|
|
progname = argv[0];
|
|
|
|
options[MODE].value = "common";
|
|
|
|
/* read command line options */
|
|
argc=u_parseArgs(argc, argv, sizeof(options)/sizeof(options[0]), options);
|
|
|
|
/* error handling, printing usage message */
|
|
/* I've decided to simply print an error and quit. This tool has too
|
|
many options to just display them all of the time. */
|
|
|
|
if(options[HELP].doesOccur || options[HELP_QUESTION_MARK].doesOccur) {
|
|
needsHelp = TRUE;
|
|
}
|
|
else {
|
|
if(!needsHelp && argc<0) {
|
|
fprintf(stderr,
|
|
"%s: error in command line argument \"%s\"\n",
|
|
progname,
|
|
argv[-argc]);
|
|
fprintf(stderr, "Run '%s --help' for help.\n", progname);
|
|
return 1;
|
|
}
|
|
|
|
|
|
#ifndef U_WINDOWS
|
|
if(!options[BLDOPT].doesOccur) {
|
|
if (pkg_getOptionsFromICUConfig(&options[BLDOPT]) != 0) {
|
|
fprintf(stderr, " required parameter is missing: -O is required \n");
|
|
fprintf(stderr, "Run '%s --help' for help.\n", progname);
|
|
return 1;
|
|
}
|
|
}
|
|
#else
|
|
if(options[BLDOPT].doesOccur) {
|
|
fprintf(stdout, "Warning: You are using the -O option which is not needed for MSVC build on Windows.\n");
|
|
}
|
|
#endif
|
|
|
|
if(!options[NAME].doesOccur) /* -O we already have - don't report it. */
|
|
{
|
|
fprintf(stderr, " required parameter -p is missing \n");
|
|
fprintf(stderr, "Run '%s --help' for help.\n", progname);
|
|
return 1;
|
|
}
|
|
|
|
if(argc == 1) {
|
|
fprintf(stderr,
|
|
"No input files specified.\n"
|
|
"Run '%s --help' for help.\n", progname);
|
|
return 1;
|
|
}
|
|
} /* end !needsHelp */
|
|
|
|
if(argc<0 || needsHelp ) {
|
|
fprintf(stderr,
|
|
"usage: %s [-options] [-] [packageFile] \n"
|
|
"\tProduce packaged ICU data from the given list(s) of files.\n"
|
|
"\t'-' by itself means to read from stdin.\n"
|
|
"\tpackageFile is a text file containing the list of files to package.\n",
|
|
progname);
|
|
|
|
fprintf(stderr, "\n options:\n");
|
|
for(i=0;i<(sizeof(options)/sizeof(options[0]));i++) {
|
|
fprintf(stderr, "%-5s -%c %s%-10s %s\n",
|
|
(i<1?"[REQ]":""),
|
|
options[i].shortName,
|
|
options[i].longName ? "or --" : " ",
|
|
options[i].longName ? options[i].longName : "",
|
|
options_help[i]);
|
|
}
|
|
|
|
fprintf(stderr, "modes: (-m option)\n");
|
|
for(i=0;i<(sizeof(modes)/sizeof(modes[0]));i++) {
|
|
fprintf(stderr, " %-9s ", modes[i].name);
|
|
if (modes[i].alt_name) {
|
|
fprintf(stderr, "/ %-9s", modes[i].alt_name);
|
|
} else {
|
|
fprintf(stderr, " ");
|
|
}
|
|
fprintf(stderr, " %s\n", modes[i].desc);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* OK, fill in the options struct */
|
|
uprv_memset(&o, 0, sizeof(o));
|
|
|
|
o.mode = options[MODE].value;
|
|
o.version = options[REVISION].doesOccur ? options[REVISION].value : 0;
|
|
|
|
o.makeArgs = NULL;
|
|
|
|
o.fcn = NULL;
|
|
|
|
for(i=0;i<sizeof(modes)/sizeof(modes[0]);i++) {
|
|
if(!uprv_strcmp(modes[i].name, o.mode)) {
|
|
o.fcn = modes[i].fcn;
|
|
break;
|
|
} else if (modes[i].alt_name && !uprv_strcmp(modes[i].alt_name, o.mode)) {
|
|
o.mode = modes[i].name;
|
|
o.fcn = modes[i].fcn;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(o.fcn == NULL) {
|
|
fprintf(stderr, "Error: invalid mode '%s' specified. Run '%s --help' to list valid modes.\n", o.mode, progname);
|
|
return 1;
|
|
}
|
|
|
|
o.shortName = options[NAME].value;
|
|
{
|
|
int32_t len = (int32_t)uprv_strlen(o.shortName);
|
|
char *csname, *cp;
|
|
const char *sp;
|
|
|
|
cp = csname = (char *) uprv_malloc((len + 1 + 1) * sizeof(*o.cShortName));
|
|
if (*(sp = o.shortName)) {
|
|
*cp++ = isalpha(*sp) ? * sp : '_';
|
|
for (++sp; *sp; ++sp) {
|
|
*cp++ = isalnum(*sp) ? *sp : '_';
|
|
}
|
|
}
|
|
*cp = 0;
|
|
|
|
o.cShortName = csname;
|
|
}
|
|
|
|
if(options[LIBNAME].doesOccur) { /* get libname from shortname, or explicit -L parameter */
|
|
o.libName = options[LIBNAME].value;
|
|
} else {
|
|
o.libName = o.shortName;
|
|
}
|
|
|
|
if(options[QUIET].doesOccur) {
|
|
o.quiet = TRUE;
|
|
} else {
|
|
o.quiet = FALSE;
|
|
}
|
|
|
|
o.verbose = options[VERBOSE].doesOccur;
|
|
|
|
#ifndef U_WINDOWS /* on UNIX, we'll just include the file... */
|
|
o.options = options[BLDOPT].value;
|
|
#endif
|
|
if(options[COPYRIGHT].doesOccur) {
|
|
o.comment = U_COPYRIGHT_STRING;
|
|
} else if (options[COMMENT].doesOccur) {
|
|
o.comment = options[COMMENT].value;
|
|
}
|
|
|
|
if( options[DESTDIR].doesOccur ) {
|
|
o.targetDir = options[DESTDIR].value;
|
|
} else {
|
|
o.targetDir = "."; /* cwd */
|
|
}
|
|
|
|
o.clean = options[CLEAN].doesOccur;
|
|
o.nooutput = options[NOOUTPUT].doesOccur;
|
|
o.rebuild = options[REBUILD].doesOccur;
|
|
|
|
if( options[TEMPDIR].doesOccur ) {
|
|
o.tmpDir = options[TEMPDIR].value;
|
|
} else {
|
|
o.tmpDir = o.targetDir;
|
|
}
|
|
|
|
if( options[INSTALL].doesOccur ) {
|
|
o.install = options[INSTALL].value;
|
|
} else {
|
|
o.install = NULL;
|
|
}
|
|
|
|
if( options[SOURCEDIR].doesOccur ) {
|
|
o.srcDir = options[SOURCEDIR].value;
|
|
} else {
|
|
o.srcDir = ".";
|
|
}
|
|
|
|
if( options[ENTRYPOINT].doesOccur ) {
|
|
o.entryName = options[ENTRYPOINT].value;
|
|
} else {
|
|
o.entryName = o.cShortName;
|
|
}
|
|
|
|
/* OK options are set up. Now the file lists. */
|
|
tail = NULL;
|
|
for( i=1; i<argc; i++) {
|
|
if ( !uprv_strcmp(argv[i] , "-") ) {
|
|
/* stdin */
|
|
if( o.hadStdin == TRUE ) {
|
|
fprintf(stderr, "Error: can't specify '-' twice!\n"
|
|
"Run '%s --help' for help.\n", progname);
|
|
return 1;
|
|
}
|
|
o.hadStdin = TRUE;
|
|
}
|
|
|
|
o.fileListFiles = pkg_appendToList(o.fileListFiles, &tail, uprv_strdup(argv[i]));
|
|
}
|
|
|
|
/* load the files */
|
|
loadLists(&o, &status);
|
|
if( U_FAILURE(status) ) {
|
|
fprintf(stderr, "error loading input file lists: %s\n", u_errorName(status));
|
|
return 2;
|
|
}
|
|
|
|
o.makeFile = "DO_NOT_USE";
|
|
|
|
|
|
if(o.nooutput == TRUE) {
|
|
return 0; /* nothing to do. */
|
|
}
|
|
|
|
result = pkg_executeOptions(&o);
|
|
|
|
if (o.cShortName != NULL) {
|
|
uprv_free((char *)o.cShortName);
|
|
}
|
|
if (o.fileListFiles != NULL) {
|
|
pkg_deleteList(o.fileListFiles);
|
|
}
|
|
if (o.filePaths != NULL) {
|
|
pkg_deleteList(o.filePaths);
|
|
}
|
|
if (o.files != NULL) {
|
|
pkg_deleteList(o.files);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
#define LN_CMD "ln -s"
|
|
#define RM_CMD "rm -f"
|
|
|
|
#define ICUDATA_RES_FILE "icudata.res"
|
|
|
|
#define MODE_COMMON 'c'
|
|
#define MODE_STATIC 's'
|
|
#define MODE_DLL 'd'
|
|
#define MODE_FILES '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] = "";
|
|
|
|
if (mode == MODE_FILES) {
|
|
// TODO: Copy files over
|
|
return result;
|
|
} else /* if (mode == MODE_COMMON || mode == MODE_STATIC || mode == MODE_DLL) */ {
|
|
uprv_strcpy(targetDir, o->targetDir);
|
|
uprv_strcat(targetDir, U_FILE_SEP_STRING);
|
|
|
|
uprv_strcpy(tmpDir, o->tmpDir);
|
|
uprv_strcat(tmpDir, U_FILE_SEP_STRING);
|
|
|
|
uprv_strcpy(datFileNamePath, tmpDir);
|
|
|
|
uprv_strcpy(datFileName, o->shortName);
|
|
uprv_strcat(datFileName, ".dat");
|
|
|
|
uprv_strcat(datFileNamePath, datFileName);
|
|
|
|
result = writePackageDatFile(datFileNamePath, o->comment, o->srcDir, o->fileListFiles->str, NULL, U_IS_BIG_ENDIAN ? 'b' : 'l');
|
|
if (result != 0) {
|
|
fprintf(stderr,"Error writing package dat file.\n");
|
|
return result;
|
|
}
|
|
if (mode == MODE_COMMON) {
|
|
char targetFileNamePath[LARGE_BUFFER_MAX_SIZE] = "";
|
|
|
|
uprv_strcpy(targetFileNamePath, targetDir);
|
|
uprv_strcat(targetFileNamePath, datFileName);
|
|
|
|
/* Move the dat file created to the target directory. */
|
|
rename(datFileNamePath, targetFileNamePath);
|
|
|
|
return result;
|
|
} else /* if (mode[0] == MODE_STATIC || mode[0] == MODE_DLL) */ {
|
|
char gencFilePath[SMALL_BUFFER_MAX_SIZE] = "";
|
|
char version_major[10] = "";
|
|
UBool reverseExt = FALSE;
|
|
|
|
if (pkg_readInFlags(o->options) != 0) {
|
|
fprintf(stderr,"Unable to open or read \"%s\" option file.\n", o->options);
|
|
return -1;
|
|
}
|
|
|
|
#ifndef U_WINDOWS
|
|
/* Get the version major number. */
|
|
if (o->version != NULL) {
|
|
for (int32_t i = 0;i < sizeof(version_major);i++) {
|
|
if (o->version[i] == '.') {
|
|
version_major[i] = 0;
|
|
break;
|
|
}
|
|
version_major[i] = o->version[i];
|
|
}
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/* Using the base libName and version number, generate the library file names. */
|
|
createFileNames(version_major, o->version, o->libName, reverseExt);
|
|
|
|
if (o->version != NULL) {
|
|
/* Check to see if a previous built data library file exists */
|
|
sprintf(checkLibFile, "%s%s", targetDir, libFileNames[LIB_FILE_VERSION_TMP]);
|
|
if (T_FileStream_file_exists(checkLibFile)) {
|
|
if (o->install != NULL) {
|
|
uprv_strcpy(libFileNames[LIB_FILE_VERSION], libFileNames[LIB_FILE_VERSION_TMP]);
|
|
result = pkg_installLibrary(o->install, targetDir);
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
pkg_checkFlag(o);
|
|
#endif
|
|
|
|
if (pkgDataFlags[GENCCODE_ASSEMBLY_TYPE][0] != 0) {
|
|
const char* genccodeAssembly = pkgDataFlags[GENCCODE_ASSEMBLY_TYPE];
|
|
|
|
/* Offset genccodeAssembly by 3 because "-a " */
|
|
if (checkAssemblyHeaderName(genccodeAssembly+3)) {
|
|
writeAssemblyCode(datFileNamePath, o->tmpDir, o->entryName, NULL, gencFilePath);
|
|
|
|
result = pkg_createWithAssemblyCode(targetDir, mode, gencFilePath);
|
|
if (result != 0) {
|
|
fprintf(stderr, "Error generating assembly code for data.\n");
|
|
return result;
|
|
} else if (mode == MODE_STATIC) {
|
|
return result;
|
|
}
|
|
} else {
|
|
fprintf(stderr,"Assembly type \"%s\" is unknown.\n", genccodeAssembly);
|
|
return -1;
|
|
}
|
|
} else {
|
|
#if defined(U_WINDOWS) || defined(U_LINUX)
|
|
writeObjectCode(datFileNamePath, o->tmpDir, o->entryName, NULL, NULL, gencFilePath);
|
|
#ifdef U_LINUX
|
|
result = pkg_generateLibraryFile(targetDir, mode, gencFilePath, NULL);
|
|
#else U_WINDOWS
|
|
return pkg_createWindowsDLL(mode, gencFilePath, o);
|
|
#endif
|
|
#else
|
|
result = pkg_createWithoutAssemblyCode(o, targetDir, mode);
|
|
#endif
|
|
if (result != 0) {
|
|
fprintf(stderr, "Error generating package data.\n");
|
|
return result;
|
|
}
|
|
}
|
|
#ifndef U_WINDOWS
|
|
/* Certain platforms uses archive library. (e.g. AIX) */
|
|
result = pkg_archiveLibrary(targetDir, o->version, reverseExt);
|
|
if (result != 0) {
|
|
fprintf(stderr, "Error creating data archive library file.\n");
|
|
return result;
|
|
}
|
|
|
|
/* Create symbolic links for the final library file. */
|
|
result = pkg_createSymLinks(targetDir);
|
|
if (result != 0) {
|
|
fprintf(stderr, "Error creating symbolic links of the data library file.\n");
|
|
return result;
|
|
}
|
|
|
|
/* Install the libraries if option was set. */
|
|
if (o->install != NULL) {
|
|
result = pkg_installLibrary(o->install, targetDir);
|
|
if (result != 0) {
|
|
fprintf(stderr, "Error installing the data library.\n");
|
|
return result;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
/*
|
|
* Given the base libName and version numbers, generate the libary file names and store it in libFileNames.
|
|
* Depending on the configuration, the library name may either end with version number or shared object suffix.
|
|
*/
|
|
static void createFileNames(const char *version_major, const char *version, const char *libName, UBool reverseExt) {
|
|
sprintf(libFileNames[LIB_FILE], "%s%s",
|
|
pkgDataFlags[LIBPREFIX],
|
|
libName);
|
|
if (version != NULL) {
|
|
#ifdef U_CYGWIN
|
|
sprintf(libFileNames[LIB_FILE_CYGWIN], "cyg%s%s.%s",
|
|
libName,
|
|
version_major,
|
|
pkgDataFlags[SO_EXT]);
|
|
|
|
sprintf(pkgDataFlags[SO_EXT], "%s.%s",
|
|
pkgDataFlags[SO_EXT],
|
|
pkgDataFlags[A_EXT]);
|
|
#else
|
|
sprintf(libFileNames[LIB_FILE_VERSION_TMP], "%s%s%s.%s",
|
|
libFileNames[LIB_FILE],
|
|
pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "",
|
|
reverseExt ? version : pkgDataFlags[SOBJ_EXT],
|
|
reverseExt ? pkgDataFlags[SOBJ_EXT] : version);
|
|
#endif
|
|
sprintf(libFileNames[LIB_FILE_VERSION_MAJOR], "%s%s%s.%s",
|
|
libFileNames[LIB_FILE],
|
|
pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "",
|
|
reverseExt ? version_major : pkgDataFlags[SO_EXT],
|
|
reverseExt ? pkgDataFlags[SO_EXT] : version_major);
|
|
|
|
libFileNames[LIB_FILE_VERSION][0] = 0;
|
|
|
|
#ifdef U_CYGWIN
|
|
/* Cygwin only deals with the version major number. */
|
|
uprv_strcpy(libFileNames[LIB_FILE_VERSION_TMP], libFileNames[LIB_FILE_VERSION_MAJOR]);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* Create the symbolic links for the final library file. */
|
|
static int32_t pkg_createSymLinks(const char *targetDir) {
|
|
char cmd[LARGE_BUFFER_MAX_SIZE];
|
|
int32_t result = 0;
|
|
|
|
#ifndef U_CYGWIN
|
|
sprintf(cmd, "cd %s && %s %s && %s %s %s",
|
|
targetDir,
|
|
RM_CMD,
|
|
libFileNames[LIB_FILE_VERSION_MAJOR],
|
|
LN_CMD,
|
|
libFileNames[LIB_FILE_VERSION],
|
|
libFileNames[LIB_FILE_VERSION_MAJOR]);
|
|
result = system(cmd);
|
|
if (result != 0) {
|
|
return result;
|
|
}
|
|
#endif
|
|
sprintf(cmd, "cd %s && %s %s.%s && %s %s %s.%s",
|
|
targetDir,
|
|
RM_CMD,
|
|
libFileNames[LIB_FILE], pkgDataFlags[SO_EXT],
|
|
LN_CMD,
|
|
libFileNames[LIB_FILE_VERSION],
|
|
libFileNames[LIB_FILE], pkgDataFlags[SO_EXT]);
|
|
|
|
result = system(cmd);
|
|
|
|
return result;
|
|
}
|
|
|
|
static int32_t pkg_installLibrary(const char *installDir, const char *targetDir) {
|
|
char cmd[SMALL_BUFFER_MAX_SIZE];
|
|
int32_t result = 0;
|
|
|
|
sprintf(cmd, "cd %s && %s %s %s%s%s",
|
|
targetDir,
|
|
pkgDataFlags[INSTALL_CMD],
|
|
libFileNames[LIB_FILE_VERSION],
|
|
installDir, U_FILE_SEP_STRING, libFileNames[LIB_FILE_VERSION]
|
|
);
|
|
|
|
result = system(cmd);
|
|
|
|
if (result != 0) {
|
|
return result;
|
|
}
|
|
|
|
return pkg_createSymLinks(installDir);
|
|
}
|
|
|
|
/* 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) {
|
|
char cmd[LARGE_BUFFER_MAX_SIZE];
|
|
int32_t result = 0;
|
|
|
|
/* If the shard object suffix and the final object suffix is different and the final object suffix and the
|
|
* archive file suffix is the same, then the final library needs to be archived.
|
|
*/
|
|
if (uprv_strcmp(pkgDataFlags[SOBJ_EXT], pkgDataFlags[SO_EXT]) != 0 && uprv_strcmp(pkgDataFlags[A_EXT], pkgDataFlags[SO_EXT]) == 0) {
|
|
sprintf(libFileNames[LIB_FILE_VERSION], "%s%s%s.%s",
|
|
libFileNames[LIB_FILE],
|
|
pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "",
|
|
reverseExt ? version : pkgDataFlags[SO_EXT],
|
|
reverseExt ? pkgDataFlags[SO_EXT] : version);
|
|
|
|
sprintf(cmd, "%s %s %s%s %s%s",
|
|
pkgDataFlags[AR],
|
|
pkgDataFlags[ARFLAGS],
|
|
targetDir,
|
|
libFileNames[LIB_FILE_VERSION],
|
|
targetDir,
|
|
libFileNames[LIB_FILE_VERSION_TMP]);
|
|
|
|
result = system(cmd);
|
|
if (result != 0) {
|
|
return result;
|
|
}
|
|
|
|
/* Remove unneeded library file. */
|
|
sprintf(cmd, "%s %s%s",
|
|
RM_CMD,
|
|
targetDir,
|
|
libFileNames[LIB_FILE_VERSION_TMP]);
|
|
|
|
result = system(cmd);
|
|
if (result != 0) {
|
|
return result;
|
|
}
|
|
|
|
} else {
|
|
uprv_strcpy(libFileNames[LIB_FILE_VERSION], libFileNames[LIB_FILE_VERSION_TMP]);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Using the compiler information from the configuration file set by -O option, generate the library file.
|
|
* command may be given to allow for a larger buffer for cmd.
|
|
*/
|
|
static int32_t pkg_generateLibraryFile(const char *targetDir, const char mode, const char *objectFile, char *command) {
|
|
int32_t result = 0;
|
|
char *cmd;
|
|
UBool cmdFree = FALSE;
|
|
|
|
if (command != NULL) {
|
|
cmd = command;
|
|
} else {
|
|
cmd = (char *)uprv_malloc(sizeof(char) * LARGE_BUFFER_MAX_SIZE);
|
|
cmdFree = TRUE;
|
|
}
|
|
|
|
if (mode == MODE_STATIC) {
|
|
sprintf(cmd, "%s %s %s%s.%s %s",
|
|
pkgDataFlags[AR],
|
|
pkgDataFlags[ARFLAGS],
|
|
targetDir,
|
|
libFileNames[LIB_FILE],
|
|
pkgDataFlags[A_EXT],
|
|
objectFile);
|
|
|
|
return system(cmd);
|
|
} else /* if (mode == MODE_DLL) */ {
|
|
#ifdef U_CYGWIN
|
|
sprintf(cmd, "%s%s%s %s -o %s%s %s %s%s %s %s",
|
|
pkgDataFlags[GENLIB],
|
|
targetDir,
|
|
libFileNames[LIB_FILE_VERSION_TMP],
|
|
pkgDataFlags[LDICUDTFLAGS],
|
|
targetDir, libFileNames[LIB_FILE_CYGWIN],
|
|
#else
|
|
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 = system(cmd);
|
|
}
|
|
|
|
if (cmdFree) {
|
|
uprv_free(cmd);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static int32_t pkg_createWithAssemblyCode(const char *targetDir, const char mode, const char *gencFilePath) {
|
|
char tempObjectFile[SMALL_BUFFER_MAX_SIZE] = "";
|
|
char cmd[LARGE_BUFFER_MAX_SIZE];
|
|
int32_t result = 0;
|
|
|
|
/* Remove the ending .s and replace it with .o for the new object file. */
|
|
uprv_strcpy(tempObjectFile, gencFilePath);
|
|
tempObjectFile[uprv_strlen(tempObjectFile)-1] = 'o';
|
|
|
|
/* Generate the object file. */
|
|
sprintf(cmd, "%s %s -o %s %s",
|
|
pkgDataFlags[COMPILER],
|
|
pkgDataFlags[LIBFLAGS],
|
|
tempObjectFile,
|
|
gencFilePath);
|
|
|
|
result = system(cmd);
|
|
if (result != 0) {
|
|
return result;
|
|
}
|
|
|
|
return pkg_generateLibraryFile(targetDir, mode, tempObjectFile, cmd);
|
|
}
|
|
|
|
/*
|
|
* Generation of the data library without assembly code needs to compile each data file
|
|
* individually and then link it all together.
|
|
*/
|
|
enum {
|
|
DATA_PREFIX_BRKITR,
|
|
DATA_PREFIX_COLL,
|
|
DATA_PREFIX_RBNF,
|
|
DATA_PREFIX_TRANSLIT,
|
|
DATA_PREFIX_LENGTH
|
|
};
|
|
const static char DATA_PREFIX[DATA_PREFIX_LENGTH][10] = {
|
|
"brkitr",
|
|
"coll",
|
|
"rbnf",
|
|
"translit"
|
|
};
|
|
static int32_t pkg_createWithoutAssemblyCode(UPKGOptions *o, const char *targetDir, const char mode) {
|
|
CharList *list = o->filePaths;
|
|
CharList *listNames = o->files;
|
|
int32_t listSize = pkg_countCharList(list);
|
|
char *buffer;
|
|
char *cmd;
|
|
int32_t result = 0;
|
|
char gencmnFile[SMALL_BUFFER_MAX_SIZE] = "";
|
|
char tempObjectFile[SMALL_BUFFER_MAX_SIZE] = "";
|
|
|
|
cmd = (char *)uprv_malloc((listSize + 2) * SMALL_BUFFER_MAX_SIZE);
|
|
buffer = (char *)uprv_malloc((listSize + 1) * SMALL_BUFFER_MAX_SIZE);
|
|
|
|
for (int32_t i = 0; i < (listSize + 1); i++) {
|
|
const char *file ;
|
|
const char *name;
|
|
|
|
if (list == NULL || listNames == NULL) {
|
|
/* list and listNames should never be NULL since we are looping through the CharList with
|
|
* the given size.
|
|
*/
|
|
result = -1;
|
|
break;
|
|
}
|
|
if (i == 0) {
|
|
/* The first iteration calls the gencmn function and initailizes the buffer. */
|
|
createCommonDataFile(o->tmpDir, o->shortName, o->entryName, NULL, o->srcDir, o->comment, o->fileListFiles->str, 0, TRUE, o->verbose, gencmnFile);
|
|
buffer[0] = 0;
|
|
} else {
|
|
char newName[SMALL_BUFFER_MAX_SIZE];
|
|
char dataName[SMALL_BUFFER_MAX_SIZE];
|
|
const char *pSubstring;
|
|
file = list->str;
|
|
name = listNames->str;
|
|
|
|
newName[0] = dataName[0] = 0;
|
|
for (int32_t n = 0; n < DATA_PREFIX_LENGTH; n++) {
|
|
/* If the name contains a prefix, alter the new name accordingly. */
|
|
pSubstring = uprv_strstr(name, DATA_PREFIX[n]);
|
|
if (pSubstring != NULL) {
|
|
char newNameTmp[SMALL_BUFFER_MAX_SIZE] = "";
|
|
const char *p = name + uprv_strlen(DATA_PREFIX[n]) + 1;
|
|
for (int32_t i = 0;;i++) {
|
|
if (p[i] == '.') {
|
|
newNameTmp[i] = '_';
|
|
continue;
|
|
}
|
|
newNameTmp[i] = p[i];
|
|
if (p[i] == 0) {
|
|
break;
|
|
}
|
|
}
|
|
sprintf(newName, "%s_%s",
|
|
DATA_PREFIX[n],
|
|
newNameTmp);
|
|
sprintf(dataName, "%s_%s",
|
|
o->shortName,
|
|
DATA_PREFIX[n]);
|
|
}
|
|
if (newName[0] != 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
writeCCode(file, o->tmpDir, dataName[0] != 0 ? dataName : o->shortName, newName[0] != 0 ? newName : NULL, gencmnFile);
|
|
}
|
|
|
|
uprv_strcpy(tempObjectFile, gencmnFile);
|
|
tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
|
|
|
|
sprintf(cmd, "%s %s -o %s %s",
|
|
pkgDataFlags[COMPILER],
|
|
pkgDataFlags[LIBFLAGS],
|
|
tempObjectFile,
|
|
gencmnFile);
|
|
result = system(cmd);
|
|
if (result != 0) {
|
|
break;
|
|
}
|
|
|
|
sprintf(buffer, "%s %s",
|
|
buffer,
|
|
tempObjectFile);
|
|
|
|
if (i > 0) {
|
|
list = list->next;
|
|
listNames = listNames->next;
|
|
}
|
|
}
|
|
|
|
/* Generate the library file. */
|
|
result = pkg_generateLibraryFile(targetDir, mode, buffer, cmd);
|
|
|
|
uprv_free(buffer);
|
|
uprv_free(cmd);
|
|
|
|
return result;
|
|
}
|
|
|
|
#ifdef U_WINDOWS
|
|
#define LINK_CMD "link.exe /nologo /release /out:"
|
|
#define LINK_FLAGS "/DLL /NOENTRY /MANIFEST:NO /base:0x4ad00000 /implib:"
|
|
#define LIB_CMD "LIB.exe /nologo /out:"
|
|
#define LIB_FILE "icudt.lib"
|
|
#define LIB_EXT ".lib"
|
|
#define DLL_EXT ".dll"
|
|
|
|
static int32_t pkg_createWindowsDLL(const char mode, const char *gencFilePath, UPKGOptions *o) {
|
|
char cmd[LARGE_BUFFER_MAX_SIZE];
|
|
if (mode == MODE_STATIC) {
|
|
char staticLibFilePath[SMALL_BUFFER_MAX_SIZE] = "";
|
|
|
|
uprv_strcpy(staticLibFilePath, o->tmpDir);
|
|
uprv_strcat(staticLibFilePath, U_FILE_SEP_STRING);
|
|
|
|
uprv_strcat(staticLibFilePath, o->entryName);
|
|
uprv_strcat(staticLibFilePath, LIB_EXT);
|
|
|
|
sprintf(cmd, "%s\"%s\" \"%s\"",
|
|
LIB_CMD,
|
|
staticLibFilePath,
|
|
gencFilePath);
|
|
} else if (mode == MODE_DLL) {
|
|
char dllFilePath[SMALL_BUFFER_MAX_SIZE] = "";
|
|
char libFilePath[SMALL_BUFFER_MAX_SIZE] = "";
|
|
char resFilePath[SMALL_BUFFER_MAX_SIZE] = "";
|
|
|
|
#ifdef CYGWINMSVC
|
|
uprv_strcpy(dllFilePath, o->targetDir);
|
|
#else
|
|
uprv_strcpy(dllFilePath, o->srcDir);
|
|
#endif
|
|
uprv_strcat(dllFilePath, U_FILE_SEP_STRING);
|
|
uprv_strcpy(libFilePath, dllFilePath);
|
|
|
|
uprv_strcpy(resFilePath, o->tmpDir);
|
|
uprv_strcat(resFilePath, U_FILE_SEP_STRING);
|
|
|
|
uprv_strcat(dllFilePath, o->entryName);
|
|
uprv_strcat(dllFilePath, DLL_EXT);
|
|
uprv_strcat(libFilePath, LIB_FILE);
|
|
uprv_strcat(resFilePath, ICUDATA_RES_FILE);
|
|
|
|
if (!T_FileStream_file_exists(resFilePath)) {
|
|
uprv_memset(resFilePath, 0, sizeof(resFilePath));
|
|
}
|
|
|
|
sprintf(cmd, "%s\"%s\" %s\"%s\" \"%s\" \"%s\"",
|
|
LINK_CMD,
|
|
dllFilePath,
|
|
LINK_FLAGS,
|
|
libFilePath,
|
|
gencFilePath,
|
|
resFilePath
|
|
);
|
|
}
|
|
|
|
return system(cmd);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Get the position after the '=' character.
|
|
*/
|
|
static int32_t flagOffset(const char *buffer, int32_t bufferSize) {
|
|
int32_t offset = 0;
|
|
|
|
for (offset = 0; offset < bufferSize;offset++) {
|
|
if (buffer[offset] == '=') {
|
|
offset++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (offset == bufferSize || (offset - 1) == bufferSize) {
|
|
offset = 0;
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
/*
|
|
* Extract the setting after the '=' and store it in flag excluding the newline character.
|
|
*/
|
|
static void extractFlag(char* buffer, int32_t bufferSize, char* flag) {
|
|
char *pBuffer;
|
|
int32_t offset;
|
|
UBool bufferWritten = FALSE;
|
|
|
|
if (buffer[0] != 0) {
|
|
/* Get the offset (i.e. position after the '=') */
|
|
offset = flagOffset(buffer, bufferSize);
|
|
pBuffer = buffer+offset;
|
|
for(int32_t i = 0;;i++) {
|
|
if (pBuffer[i+1] == 0) {
|
|
/* Indicates a new line character. End here. */
|
|
flag[i] = 0;
|
|
break;
|
|
}
|
|
|
|
flag[i] = pBuffer[i];
|
|
if (i == 0) {
|
|
bufferWritten = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bufferWritten) {
|
|
flag[0] = 0;
|
|
}
|
|
}
|
|
|
|
static void pkg_checkFlag(UPKGOptions *o) {
|
|
char *flag = NULL;
|
|
int32_t length = 0;
|
|
#ifdef U_AIX
|
|
char tmpbuffer[SMALL_BUFFER_MAX_SIZE];
|
|
const char MAP_FILE_EXT[] = ".map";
|
|
FileStream *f = NULL;
|
|
char mapFile[SMALL_BUFFER_MAX_SIZE] = "";
|
|
int32_t start = -1;
|
|
int32_t count = 0;
|
|
|
|
flag = pkgDataFlags[BIR_FLAGS];
|
|
length = uprv_strlen(pkgDataFlags[BIR_FLAGS]);
|
|
|
|
for (int32_t i = 0; i < length; i++) {
|
|
if (flag[i] == MAP_FILE_EXT[count]) {
|
|
if (count == 0) {
|
|
start = i;
|
|
}
|
|
count++;
|
|
} else {
|
|
count = 0;
|
|
}
|
|
|
|
if (count == uprv_strlen(MAP_FILE_EXT)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (start >= 0) {
|
|
int32_t index = 0;
|
|
for (int32_t i = 0;;i++) {
|
|
if (i == start) {
|
|
for (int32_t n = 0;;n++) {
|
|
if (o->shortName[n] == 0) {
|
|
break;
|
|
}
|
|
tmpbuffer[index++] = o->shortName[n];
|
|
}
|
|
}
|
|
|
|
tmpbuffer[index++] = flag[i];
|
|
|
|
if (flag[i] == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
uprv_memset(flag, 0, length);
|
|
uprv_strcpy(flag, tmpbuffer);
|
|
|
|
uprv_strcpy(mapFile, o->shortName);
|
|
uprv_strcat(mapFile, MAP_FILE_EXT);
|
|
|
|
f = T_FileStream_open(mapFile, "w");
|
|
if (f == NULL) {
|
|
fprintf(stderr,"Unable to create map file: %s.\n", mapFile);
|
|
return;
|
|
}
|
|
|
|
sprintf(tmpbuffer, "%s_dat ", o->entryName);
|
|
|
|
T_FileStream_writeLine(f, tmpbuffer);
|
|
|
|
T_FileStream_close(f);
|
|
}
|
|
#elif defined(U_CYGWIN)
|
|
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);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Opens the given fileName and reads in the information storing the data in pkgDataFlags.
|
|
*/
|
|
static int32_t pkg_readInFlags(const char *fileName) {
|
|
int32_t result = 0;
|
|
|
|
#ifdef U_WINDOWS
|
|
/* Zero out the flags since it is not being used. */
|
|
for (int32_t i = 0; i < PKGDATA_FLAGS_SIZE; i++) {
|
|
pkgDataFlags[i][0] = 0;
|
|
}
|
|
|
|
#else
|
|
char buffer[LARGE_BUFFER_MAX_SIZE];
|
|
|
|
FileStream *f = T_FileStream_open(fileName, "r");
|
|
if (f == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
for (int32_t i = 0; i < PKGDATA_FLAGS_SIZE; i++) {
|
|
if (T_FileStream_readLine(f, buffer, LARGE_BUFFER_MAX_SIZE) == NULL) {
|
|
result = -1;
|
|
break;
|
|
}
|
|
|
|
extractFlag(buffer, LARGE_BUFFER_MAX_SIZE, pkgDataFlags[i]);
|
|
}
|
|
|
|
T_FileStream_close(f);
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
#if 0
|
|
{
|
|
rc = system(cmd);
|
|
|
|
if(rc < 0) {
|
|
fprintf(stderr, "# Failed, rc=%d\n", rc);
|
|
}
|
|
|
|
return rc < 128 ? rc : (rc >> 8);
|
|
}
|
|
#endif
|
|
|
|
|
|
static void loadLists(UPKGOptions *o, UErrorCode *status)
|
|
{
|
|
CharList *l, *tail = NULL, *tail2 = NULL;
|
|
FileStream *in;
|
|
char line[16384];
|
|
char *linePtr, *lineNext;
|
|
const uint32_t lineMax = 16300;
|
|
char tmp[1024];
|
|
char *s;
|
|
int32_t ln=0; /* line number */
|
|
|
|
for(l = o->fileListFiles; l; l = l->next) {
|
|
if(o->verbose) {
|
|
fprintf(stdout, "# Reading %s..\n", l->str);
|
|
}
|
|
/* TODO: stdin */
|
|
in = T_FileStream_open(l->str, "r"); /* open files list */
|
|
|
|
if(!in) {
|
|
fprintf(stderr, "Error opening <%s>.\n", l->str);
|
|
*status = U_FILE_ACCESS_ERROR;
|
|
return;
|
|
}
|
|
|
|
while(T_FileStream_readLine(in, line, sizeof(line))!=NULL) { /* for each line */
|
|
ln++;
|
|
if(uprv_strlen(line)>lineMax) {
|
|
fprintf(stderr, "%s:%d - line too long (over %d chars)\n", l->str, (int)ln, (int)lineMax);
|
|
exit(1);
|
|
}
|
|
/* remove spaces at the beginning */
|
|
linePtr = line;
|
|
while(isspace(*linePtr)) {
|
|
linePtr++;
|
|
}
|
|
s=linePtr;
|
|
/* remove trailing newline characters */
|
|
while(*s!=0) {
|
|
if(*s=='\r' || *s=='\n') {
|
|
*s=0;
|
|
break;
|
|
}
|
|
++s;
|
|
}
|
|
if((*linePtr == 0) || (*linePtr == '#')) {
|
|
continue; /* comment or empty line */
|
|
}
|
|
|
|
/* Now, process the line */
|
|
lineNext = NULL;
|
|
|
|
while(linePtr && *linePtr) { /* process space-separated items */
|
|
while(*linePtr == ' ') {
|
|
linePtr++;
|
|
}
|
|
/* Find the next quote */
|
|
if(linePtr[0] == '"')
|
|
{
|
|
lineNext = uprv_strchr(linePtr+1, '"');
|
|
if(lineNext == NULL) {
|
|
fprintf(stderr, "%s:%d - missing trailing double quote (\")\n",
|
|
l->str, (int)ln);
|
|
exit(1);
|
|
} else {
|
|
lineNext++;
|
|
if(*lineNext) {
|
|
if(*lineNext != ' ') {
|
|
fprintf(stderr, "%s:%d - malformed quoted line at position %d, expected ' ' got '%c'\n",
|
|
l->str, (int)ln, (int)(lineNext-line), (*lineNext)?*lineNext:'0');
|
|
exit(1);
|
|
}
|
|
*lineNext = 0;
|
|
lineNext++;
|
|
}
|
|
}
|
|
} else {
|
|
lineNext = uprv_strchr(linePtr, ' ');
|
|
if(lineNext) {
|
|
*lineNext = 0; /* terminate at space */
|
|
lineNext++;
|
|
}
|
|
}
|
|
|
|
/* add the file */
|
|
s = (char*)getLongPathname(linePtr);
|
|
|
|
/* normal mode.. o->files is just the bare list without package names */
|
|
o->files = pkg_appendToList(o->files, &tail, uprv_strdup(linePtr));
|
|
if(uprv_pathIsAbsolute(s)) {
|
|
fprintf(stderr, "pkgdata: Error: absolute path encountered. Old style paths are not supported. Use relative paths such as 'fur.res' or 'translit%cfur.res'.\n\tBad path: '%s'\n", U_FILE_SEP_CHAR, s);
|
|
exit(U_ILLEGAL_ARGUMENT_ERROR);
|
|
}
|
|
uprv_strcpy(tmp, o->srcDir);
|
|
uprv_strcat(tmp, o->srcDir[uprv_strlen(o->srcDir)-1]==U_FILE_SEP_CHAR?"":U_FILE_SEP_STRING);
|
|
uprv_strcat(tmp, s);
|
|
o->filePaths = pkg_appendToList(o->filePaths, &tail2, uprv_strdup(tmp));
|
|
linePtr = lineNext;
|
|
} /* for each entry on line */
|
|
} /* for each line */
|
|
T_FileStream_close(in);
|
|
} /* for each file list file */
|
|
}
|
|
|
|
/* Try calling icu-config directly to get the option file. */
|
|
static int32_t pkg_getOptionsFromICUConfig(UOption *option) {
|
|
#if U_HAVE_POPEN
|
|
FILE *p;
|
|
size_t n;
|
|
static char buf[512] = "";
|
|
const char cmd[] = "icu-config --incpkgdatafile";
|
|
|
|
p = popen(cmd, "r");
|
|
|
|
if(p == NULL)
|
|
{
|
|
fprintf(stderr, "%s: icu-config: No icu-config found. (fix PATH or use -O option)\n", progname);
|
|
return -1;
|
|
}
|
|
|
|
n = fread(buf, 1, 511, p);
|
|
|
|
pclose(p);
|
|
|
|
if(n<=0)
|
|
{
|
|
fprintf(stderr,"%s: icu-config: Could not read from icu-config. (fix PATH or use -O option)\n", progname);
|
|
return -1;
|
|
}
|
|
|
|
for (int32_t length = strlen(buf) - 1; length >= 0; length--) {
|
|
if (buf[length] == '\n' || buf[length] == ' ') {
|
|
buf[length] = 0;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(buf[strlen(buf)-1]=='\n')
|
|
{
|
|
buf[strlen(buf)-1]=0;
|
|
}
|
|
|
|
if(buf[0] == 0)
|
|
{
|
|
fprintf(stderr, "%s: icu-config: invalid response from icu-config (fix PATH or use -O option)\n", progname);
|
|
return -1;
|
|
}
|
|
|
|
option->value = buf;
|
|
option->doesOccur = TRUE;
|
|
|
|
return 0;
|
|
#endif
|
|
return -1;
|
|
}
|
|
/* Try calling icu-config directly to get information */
|
|
static void fillInMakefileFromICUConfig(UOption *option)
|
|
{
|
|
#if 0
|
|
#if U_HAVE_POPEN
|
|
FILE *p;
|
|
size_t n;
|
|
static char buf[512] = "";
|
|
static const char cmd[] = "icu-config --incfile";
|
|
|
|
if(options[5].doesOccur)
|
|
{
|
|
/* informational */
|
|
fprintf(stderr, "%s: No -O option found, trying '%s'.\n", progname, cmd);
|
|
}
|
|
|
|
p = popen(cmd, "r");
|
|
|
|
if(p == NULL)
|
|
{
|
|
fprintf(stderr, "%s: icu-config: No icu-config found. (fix PATH or use -O option)\n", progname);
|
|
return;
|
|
}
|
|
|
|
n = fread(buf, 1, 511, p);
|
|
|
|
pclose(p);
|
|
|
|
if(n<=0)
|
|
{
|
|
fprintf(stderr,"%s: icu-config: Could not read from icu-config. (fix PATH or use -O option)\n", progname);
|
|
return;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
if(options[5].doesOccur)
|
|
{
|
|
/* informational */
|
|
fprintf(stderr, "%s: icu-config: using '-O %s'\n", progname, buf);
|
|
}
|
|
option->value = buf;
|
|
option->doesOccur = TRUE;
|
|
#else /* ! U_HAVE_POPEN */
|
|
|
|
#ifdef U_WINDOWS
|
|
char pathbuffer[_MAX_PATH] = {0};
|
|
char *fullEXEpath = NULL;
|
|
char *pathstuff = NULL;
|
|
|
|
if (strchr(progname, U_FILE_SEP_CHAR) != NULL || strchr(progname, U_FILE_ALT_SEP_CHAR) != NULL) {
|
|
/* pkgdata was executed with relative path */
|
|
fullEXEpath = _fullpath(pathbuffer, progname, sizeof(pathbuffer));
|
|
pathstuff = (char *)options[1].value;
|
|
|
|
if (fullEXEpath) {
|
|
pathstuff = strrchr(fullEXEpath, U_FILE_SEP_CHAR);
|
|
if (pathstuff) {
|
|
pathstuff[1] = 0;
|
|
uprv_memmove(fullEXEpath + 2, fullEXEpath, uprv_strlen(fullEXEpath)+1);
|
|
fullEXEpath[0] = PKGDATA_DERIVED_PATH;
|
|
fullEXEpath[1] = ':';
|
|
option->value = uprv_strdup(fullEXEpath);
|
|
option->doesOccur = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/* pkgdata was executed from the path */
|
|
/* Search for file in PATH environment variable: */
|
|
_searchenv("pkgdata.exe", "PATH", pathbuffer );
|
|
if( *pathbuffer != '\0' ) {
|
|
fullEXEpath = pathbuffer;
|
|
pathstuff = strrchr(pathbuffer, U_FILE_SEP_CHAR);
|
|
if (pathstuff) {
|
|
pathstuff[1] = 0;
|
|
uprv_memmove(fullEXEpath + 2, fullEXEpath, uprv_strlen(fullEXEpath)+1);
|
|
fullEXEpath[0] = PKGDATA_DERIVED_PATH;
|
|
fullEXEpath[1] = ':';
|
|
option->value = uprv_strdup(fullEXEpath);
|
|
option->doesOccur = TRUE;
|
|
}
|
|
}
|
|
}
|
|
/* else can't determine the path */
|
|
#endif
|
|
|
|
/* no popen available */
|
|
/* Put other OS specific ways to search for the Makefile.inc type
|
|
information or else fail.. */
|
|
|
|
#endif
|
|
#endif /* End of #if 0 */
|
|
}
|