Home | History | Annotate | Download | only in pkgdata
      1 /******************************************************************************
      2  *   Copyright (C) 2000-2009, International Business Machines
      3  *   Corporation and others.  All Rights Reserved.
      4  *******************************************************************************
      5  *   file name:  pkgdata.c
      6  *   encoding:   ANSI X3.4 (1968)
      7  *   tab size:   8 (not used)
      8  *   indentation:4
      9  *
     10  *   created on: 2000may15
     11  *   created by: Steven \u24C7 Loomis
     12  *
     13  *   This program packages the ICU data into different forms
     14  *   (DLL, common data, etc.)
     15  */
     16 
     17 /*
     18  * We define _XOPEN_SOURCE so that we can get popen and pclose.
     19  */
     20 #if !defined(_XOPEN_SOURCE)
     21 #if __STDC_VERSION__ >= 199901L
     22 /* It is invalid to compile an XPG3, XPG4, XPG4v2 or XPG5 application using c99 on Solaris */
     23 #define _XOPEN_SOURCE 600
     24 #else
     25 #define _XOPEN_SOURCE 4
     26 #endif
     27 #endif
     28 
     29 
     30 #include "unicode/utypes.h"
     31 
     32 #if U_HAVE_POPEN
     33 #if defined(U_CYGWIN) && defined(__STRICT_ANSI__)
     34 /* popen/pclose aren't defined in strict ANSI on Cygwin */
     35 #undef __STRICT_ANSI__
     36 #endif
     37 #endif
     38 
     39 #include "unicode/putil.h"
     40 #include "cmemory.h"
     41 #include "cstring.h"
     42 #include "filestrm.h"
     43 #include "toolutil.h"
     44 #include "unicode/uclean.h"
     45 #include "unewdata.h"
     46 #include "uoptions.h"
     47 #include "putilimp.h"
     48 #include "package.h"
     49 #include "pkg_icu.h"
     50 #include "pkg_genc.h"
     51 #include "pkg_gencmn.h"
     52 #include "flagparser.h"
     53 #include "filetools.h"
     54 
     55 
     56 #if U_HAVE_POPEN
     57 # include <unistd.h>
     58 #endif
     59 #include <stdio.h>
     60 #include <stdlib.h>
     61 
     62 U_CDECL_BEGIN
     63 #include "pkgtypes.h"
     64 U_CDECL_END
     65 
     66 #ifdef U_WINDOWS
     67 #ifdef __GNUC__
     68 #define WINDOWS_WITH_GNUC
     69 #else
     70 #define WINDOWS_WITH_MSVC
     71 #endif
     72 #endif
     73 #if !defined(WINDOWS_WITH_MSVC) && !defined(U_LINUX)
     74 #define BUILD_DATA_WITHOUT_ASSEMBLY
     75 #endif
     76 #if defined(WINDOWS_WITH_MSVC) || defined(U_LINUX)
     77 #define CAN_WRITE_OBJ_CODE
     78 #endif
     79 
     80 /*
     81  * When building the data library without assembly,
     82  * some platforms use a single c code file for all of
     83  * the data to generate the final data library. This can
     84  * increase the performance of the pkdata tool.
     85  */
     86 #if defined(OS400)
     87 #define USE_SINGLE_CCODE_FILE
     88 #endif
     89 
     90 /* Need to fix the file seperator character when using MinGW. */
     91 #ifdef WINDOWS_WITH_GNUC
     92 #define PKGDATA_FILE_SEP_STRING "/"
     93 #else
     94 #define PKGDATA_FILE_SEP_STRING U_FILE_SEP_STRING
     95 #endif
     96 
     97 #define LARGE_BUFFER_MAX_SIZE 2048
     98 #define SMALL_BUFFER_MAX_SIZE 512
     99 
    100 static void loadLists(UPKGOptions *o, UErrorCode *status);
    101 
    102 static int32_t pkg_executeOptions(UPKGOptions *o);
    103 
    104 #ifdef WINDOWS_WITH_MSVC
    105 static int32_t pkg_createWindowsDLL(const char mode, const char *gencFilePath, UPKGOptions *o);
    106 #endif
    107 static int32_t pkg_createSymLinks(const char *targetDir);
    108 static int32_t pkg_installLibrary(const char *installDir, const char *dir);
    109 static int32_t pkg_installFileMode(const char *installDir, const char *srcDir, const char *fileListName);
    110 
    111 #ifdef BUILD_DATA_WITHOUT_ASSEMBLY
    112 static int32_t pkg_createWithoutAssemblyCode(UPKGOptions *o, const char *targetDir, const char mode);
    113 #endif
    114 
    115 static int32_t pkg_createWithAssemblyCode(const char *targetDir, const char mode, const char *gencFilePath);
    116 static int32_t pkg_generateLibraryFile(const char *targetDir, const char mode, const char *objectFile, char *command = NULL);
    117 static int32_t pkg_archiveLibrary(const char *targetDir, const char *version, UBool reverseExt);
    118 static void createFileNames(const char *version_major, const char *version, const char *libName, const UBool reverseExt);
    119 
    120 static int32_t pkg_getOptionsFromICUConfig(UOption *option);
    121 
    122 enum {
    123     NAME,
    124     BLDOPT,
    125     MODE,
    126     HELP,
    127     HELP_QUESTION_MARK,
    128     VERBOSE,
    129     COPYRIGHT,
    130     COMMENT,
    131     DESTDIR,
    132     REBUILD,
    133     TEMPDIR,
    134     INSTALL,
    135     SOURCEDIR,
    136     ENTRYPOINT,
    137     REVISION,
    138     FORCE_PREFIX,
    139     LIBNAME,
    140     QUIET
    141 };
    142 
    143 /* This sets the modes that are available */
    144 static struct {
    145     const char *name, *alt_name;
    146     const char *desc;
    147 } modes[] = {
    148         { "files", 0,           "Uses raw data files (no effect). Installation copies all files to the target location." },
    149 #ifdef U_WINDOWS
    150         { "dll",    "library",  "Generates one common data file and one shared library, <package>.dll"},
    151         { "common", "archive",  "Generates just the common file, <package>.dat"},
    152         { "static", "static",   "Generates one statically linked library, " LIB_PREFIX "<package>" UDATA_LIB_SUFFIX }
    153 #else
    154 #ifdef UDATA_SO_SUFFIX
    155         { "dll",    "library",  "Generates one shared library, <package>" UDATA_SO_SUFFIX },
    156 #endif
    157         { "common", "archive",  "Generates one common data file, <package>.dat" },
    158         { "static", "static",   "Generates one statically linked library, " LIB_PREFIX "<package>" UDATA_LIB_SUFFIX }
    159 #endif
    160 };
    161 
    162 static UOption options[]={
    163     /*00*/    UOPTION_DEF( "name",    'p', UOPT_REQUIRES_ARG),
    164     /*01*/    UOPTION_DEF( "bldopt",  'O', UOPT_REQUIRES_ARG), /* on Win32 it is release or debug */
    165     /*02*/    UOPTION_DEF( "mode",    'm', UOPT_REQUIRES_ARG),
    166     /*03*/    UOPTION_HELP_H,                                   /* -h */
    167     /*04*/    UOPTION_HELP_QUESTION_MARK,                       /* -? */
    168     /*05*/    UOPTION_VERBOSE,                                  /* -v */
    169     /*06*/    UOPTION_COPYRIGHT,                                /* -c */
    170     /*07*/    UOPTION_DEF( "comment", 'C', UOPT_REQUIRES_ARG),
    171     /*08*/    UOPTION_DESTDIR,                                  /* -d */
    172     /*11*/    UOPTION_DEF( "rebuild", 'F', UOPT_NO_ARG),
    173     /*12*/    UOPTION_DEF( "tempdir", 'T', UOPT_REQUIRES_ARG),
    174     /*13*/    UOPTION_DEF( "install", 'I', UOPT_REQUIRES_ARG),
    175     /*14*/    UOPTION_SOURCEDIR ,
    176     /*15*/    UOPTION_DEF( "entrypoint", 'e', UOPT_REQUIRES_ARG),
    177     /*16*/    UOPTION_DEF( "revision", 'r', UOPT_REQUIRES_ARG),
    178     /*17*/    UOPTION_DEF( "force-prefix", 'f', UOPT_NO_ARG),
    179     /*18*/    UOPTION_DEF( "libname", 'L', UOPT_REQUIRES_ARG),
    180     /*19*/    UOPTION_DEF( "quiet", 'q', UOPT_NO_ARG)
    181 };
    182 
    183 enum {
    184     GENCCODE_ASSEMBLY_TYPE,
    185     SO_EXT,
    186     SOBJ_EXT,
    187     A_EXT,
    188     LIBPREFIX,
    189     LIB_EXT_ORDER,
    190     COMPILER,
    191     LIBFLAGS,
    192     GENLIB,
    193     LDICUDTFLAGS,
    194     LD_SONAME,
    195     RPATH_FLAGS,
    196     BIR_FLAGS,
    197     AR,
    198     ARFLAGS,
    199     RANLIB,
    200     INSTALL_CMD,
    201     PKGDATA_FLAGS_SIZE
    202 };
    203 static char **pkgDataFlags = NULL;
    204 
    205 enum {
    206     LIB_FILE,
    207     LIB_FILE_VERSION_MAJOR,
    208     LIB_FILE_VERSION,
    209     LIB_FILE_VERSION_TMP,
    210 #ifdef U_CYGWIN
    211     LIB_FILE_CYGWIN,
    212 #endif
    213     LIB_FILENAMES_SIZE
    214 };
    215 static char libFileNames[LIB_FILENAMES_SIZE][256];
    216 
    217 static void pkg_checkFlag(UPKGOptions *o);
    218 
    219 const char options_help[][320]={
    220     "Set the data name",
    221 #ifdef U_MAKE_IS_NMAKE
    222     "The directory where the ICU is located (e.g. <ICUROOT> which contains the bin directory)",
    223 #else
    224     "Specify options for the builder.",
    225 #endif
    226     "Specify the mode of building (see below; default: common)",
    227     "This usage text",
    228     "This usage text",
    229     "Make the output verbose",
    230     "Use the standard ICU copyright",
    231     "Use a custom comment (instead of the copyright)",
    232     "Specify the destination directory for files",
    233     "Force rebuilding of all data",
    234     "Specify temporary dir (default: output dir)",
    235     "Install the data (specify target)",
    236     "Specify a custom source directory",
    237     "Specify a custom entrypoint name (default: short name)",
    238     "Specify a version when packaging in DLL or static mode",
    239     "Add package to all file names if not present",
    240     "Library name to build (if different than package name)",
    241     "Quite mode. (e.g. Do not output a readme file for static libraries)"
    242 };
    243 
    244 const char  *progname = "PKGDATA";
    245 
    246 int
    247 main(int argc, char* argv[]) {
    248     int result = 0;
    249     /* FileStream  *out; */
    250     UPKGOptions  o;
    251     CharList    *tail;
    252     UBool        needsHelp = FALSE;
    253     UErrorCode   status = U_ZERO_ERROR;
    254     /* char         tmp[1024]; */
    255     uint32_t i;
    256     int32_t n;
    257 
    258     U_MAIN_INIT_ARGS(argc, argv);
    259 
    260     progname = argv[0];
    261 
    262     options[MODE].value = "common";
    263 
    264     /* read command line options */
    265     argc=u_parseArgs(argc, argv, sizeof(options)/sizeof(options[0]), options);
    266 
    267     /* error handling, printing usage message */
    268     /* I've decided to simply print an error and quit. This tool has too
    269     many options to just display them all of the time. */
    270 
    271     if(options[HELP].doesOccur || options[HELP_QUESTION_MARK].doesOccur) {
    272         needsHelp = TRUE;
    273     }
    274     else {
    275         if(!needsHelp && argc<0) {
    276             fprintf(stderr,
    277                 "%s: error in command line argument \"%s\"\n",
    278                 progname,
    279                 argv[-argc]);
    280             fprintf(stderr, "Run '%s --help' for help.\n", progname);
    281             return 1;
    282         }
    283 
    284 
    285 #ifndef WINDOWS_WITH_MSVC
    286         if(!options[BLDOPT].doesOccur) {
    287             if (pkg_getOptionsFromICUConfig(&options[BLDOPT]) != 0) {
    288                 fprintf(stderr, " required parameter is missing: -O is required \n");
    289                 fprintf(stderr, "Run '%s --help' for help.\n", progname);
    290                 return 1;
    291             }
    292         }
    293 #else
    294         if(options[BLDOPT].doesOccur) {
    295             fprintf(stdout, "Warning: You are using the -O option which is not needed for MSVC build on Windows.\n");
    296         }
    297 #endif
    298 
    299         if(!options[NAME].doesOccur) /* -O we already have - don't report it. */
    300         {
    301             fprintf(stderr, " required parameter -p is missing \n");
    302             fprintf(stderr, "Run '%s --help' for help.\n", progname);
    303             return 1;
    304         }
    305 
    306         if(argc == 1) {
    307             fprintf(stderr,
    308                 "No input files specified.\n"
    309                 "Run '%s --help' for help.\n", progname);
    310             return 1;
    311         }
    312     }   /* end !needsHelp */
    313 
    314     if(argc<0 || needsHelp  ) {
    315         fprintf(stderr,
    316             "usage: %s [-options] [-] [packageFile] \n"
    317             "\tProduce packaged ICU data from the given list(s) of files.\n"
    318             "\t'-' by itself means to read from stdin.\n"
    319             "\tpackageFile is a text file containing the list of files to package.\n",
    320             progname);
    321 
    322         fprintf(stderr, "\n options:\n");
    323         for(i=0;i<(sizeof(options)/sizeof(options[0]));i++) {
    324             fprintf(stderr, "%-5s -%c %s%-10s  %s\n",
    325                 (i<1?"[REQ]":""),
    326                 options[i].shortName,
    327                 options[i].longName ? "or --" : "     ",
    328                 options[i].longName ? options[i].longName : "",
    329                 options_help[i]);
    330         }
    331 
    332         fprintf(stderr, "modes: (-m option)\n");
    333         for(i=0;i<(sizeof(modes)/sizeof(modes[0]));i++) {
    334             fprintf(stderr, "   %-9s ", modes[i].name);
    335             if (modes[i].alt_name) {
    336                 fprintf(stderr, "/ %-9s", modes[i].alt_name);
    337             } else {
    338                 fprintf(stderr, "           ");
    339             }
    340             fprintf(stderr, "  %s\n", modes[i].desc);
    341         }
    342         return 1;
    343     }
    344 
    345     /* OK, fill in the options struct */
    346     uprv_memset(&o, 0, sizeof(o));
    347 
    348     o.mode      = options[MODE].value;
    349     o.version   = options[REVISION].doesOccur ? options[REVISION].value : 0;
    350 
    351     o.shortName = options[NAME].value;
    352     {
    353         int32_t len = (int32_t)uprv_strlen(o.shortName);
    354         char *csname, *cp;
    355         const char *sp;
    356 
    357         cp = csname = (char *) uprv_malloc((len + 1 + 1) * sizeof(*o.cShortName));
    358         if (*(sp = o.shortName)) {
    359             *cp++ = isalpha(*sp) ? * sp : '_';
    360             for (++sp; *sp; ++sp) {
    361                 *cp++ = isalnum(*sp) ? *sp : '_';
    362             }
    363         }
    364         *cp = 0;
    365 
    366         o.cShortName = csname;
    367     }
    368 
    369     if(options[LIBNAME].doesOccur) { /* get libname from shortname, or explicit -L parameter */
    370       o.libName = options[LIBNAME].value;
    371     } else {
    372       o.libName = o.shortName;
    373     }
    374 
    375     if(options[QUIET].doesOccur) {
    376       o.quiet = TRUE;
    377     } else {
    378       o.quiet = FALSE;
    379     }
    380 
    381     o.verbose   = options[VERBOSE].doesOccur;
    382 
    383 #ifndef WINDOWS_WITH_MSVC /* on UNIX, we'll just include the file... */
    384     o.options   = options[BLDOPT].value;
    385 #endif
    386     if(options[COPYRIGHT].doesOccur) {
    387         o.comment = U_COPYRIGHT_STRING;
    388     } else if (options[COMMENT].doesOccur) {
    389         o.comment = options[COMMENT].value;
    390     }
    391 
    392     if( options[DESTDIR].doesOccur ) {
    393         o.targetDir = options[DESTDIR].value;
    394     } else {
    395         o.targetDir = ".";  /* cwd */
    396     }
    397 
    398     o.rebuild   = options[REBUILD].doesOccur;
    399 
    400     if( options[TEMPDIR].doesOccur ) {
    401         o.tmpDir    = options[TEMPDIR].value;
    402     } else {
    403         o.tmpDir    = o.targetDir;
    404     }
    405 
    406     if( options[INSTALL].doesOccur ) {
    407         o.install  = options[INSTALL].value;
    408     } else {
    409         o.install = NULL;
    410     }
    411 
    412     if( options[SOURCEDIR].doesOccur ) {
    413         o.srcDir   = options[SOURCEDIR].value;
    414     } else {
    415         o.srcDir   = ".";
    416     }
    417 
    418     if( options[ENTRYPOINT].doesOccur ) {
    419         o.entryName = options[ENTRYPOINT].value;
    420     } else {
    421         o.entryName = o.cShortName;
    422     }
    423 
    424     /* OK options are set up. Now the file lists. */
    425     tail = NULL;
    426     for( n=1; n<argc; n++) {
    427         o.fileListFiles = pkg_appendToList(o.fileListFiles, &tail, uprv_strdup(argv[n]));
    428     }
    429 
    430     /* load the files */
    431     loadLists(&o, &status);
    432     if( U_FAILURE(status) ) {
    433         fprintf(stderr, "error loading input file lists: %s\n", u_errorName(status));
    434         return 2;
    435     }
    436 
    437     result = pkg_executeOptions(&o);
    438 
    439     if (pkgDataFlags != NULL) {
    440         for (n = 0; n < PKGDATA_FLAGS_SIZE; n++) {
    441             if (pkgDataFlags[n] != NULL) {
    442                 uprv_free(pkgDataFlags[n]);
    443             }
    444         }
    445         uprv_free(pkgDataFlags);
    446     }
    447 
    448     if (o.cShortName != NULL) {
    449         uprv_free((char *)o.cShortName);
    450     }
    451     if (o.fileListFiles != NULL) {
    452         pkg_deleteList(o.fileListFiles);
    453     }
    454     if (o.filePaths != NULL) {
    455         pkg_deleteList(o.filePaths);
    456     }
    457     if (o.files != NULL) {
    458         pkg_deleteList(o.files);
    459     }
    460 
    461     return result;
    462 }
    463 
    464 #define LN_CMD "ln -s"
    465 #define RM_CMD "rm -f"
    466 
    467 #define MODE_COMMON 'c'
    468 #define MODE_STATIC 's'
    469 #define MODE_DLL    'd'
    470 #define MODE_FILES  'f'
    471 
    472 static int32_t pkg_executeOptions(UPKGOptions *o) {
    473     UErrorCode status = U_ZERO_ERROR;
    474     int32_t result = 0;
    475 //    char cmd[SMALL_BUFFER_MAX_SIZE] = "";
    476     const char mode = o->mode[0];
    477     char targetDir[SMALL_BUFFER_MAX_SIZE] = "";
    478     char tmpDir[SMALL_BUFFER_MAX_SIZE] = "";
    479     char datFileName[SMALL_BUFFER_MAX_SIZE] = "";
    480     char datFileNamePath[LARGE_BUFFER_MAX_SIZE] = "";
    481     char checkLibFile[LARGE_BUFFER_MAX_SIZE] = "";
    482 
    483     /* Initialize pkgdataFlags */
    484     pkgDataFlags = (char**)uprv_malloc(sizeof(char*) * PKGDATA_FLAGS_SIZE);
    485     if (pkgDataFlags != NULL) {
    486         for (int32_t i = 0; i < PKGDATA_FLAGS_SIZE; i++) {
    487             pkgDataFlags[i] = (char*)uprv_malloc(sizeof(char) * SMALL_BUFFER_MAX_SIZE);
    488             if (pkgDataFlags[i] != NULL) {
    489                 pkgDataFlags[i][0] = 0;
    490             } else {
    491                 fprintf(stderr,"Error allocating memory for pkgDataFlags.\n");
    492                 return -1;
    493             }
    494         }
    495     } else {
    496         fprintf(stderr,"Error allocating memory for pkgDataFlags.\n");
    497         return -1;
    498     }
    499 #ifndef WINDOWS_WITH_MSVC
    500     /* Read in options file. */
    501     parseFlagsFile(o->options, pkgDataFlags, SMALL_BUFFER_MAX_SIZE, (int32_t)PKGDATA_FLAGS_SIZE, &status);
    502     if (U_FAILURE(status)) {
    503         fprintf(stderr,"Unable to open or read \"%s\" option file.\n", o->options);
    504         return -1;
    505     }
    506 #endif
    507     if (mode == MODE_FILES) {
    508         /* Copy the raw data to the installation directory. */
    509         if (o->install != NULL) {
    510             uprv_strcpy(targetDir, o->install);
    511             if (o->shortName != NULL) {
    512                 uprv_strcat(targetDir, PKGDATA_FILE_SEP_STRING);
    513                 uprv_strcat(targetDir, o->shortName);
    514             }
    515             result = pkg_installFileMode(targetDir, o->srcDir, o->fileListFiles->str);
    516         }
    517         return result;
    518     } else /* if (mode == MODE_COMMON || mode == MODE_STATIC || mode == MODE_DLL) */ {
    519         uprv_strcpy(targetDir, o->targetDir);
    520         uprv_strcat(targetDir, PKGDATA_FILE_SEP_STRING);
    521 
    522         uprv_strcpy(tmpDir, o->tmpDir);
    523         uprv_strcat(tmpDir, PKGDATA_FILE_SEP_STRING);
    524 
    525         uprv_strcpy(datFileNamePath, tmpDir);
    526 
    527         uprv_strcpy(datFileName, o->shortName);
    528         uprv_strcat(datFileName, UDATA_CMN_SUFFIX);
    529 
    530         uprv_strcat(datFileNamePath, datFileName);
    531 
    532         result = writePackageDatFile(datFileNamePath, o->comment, o->srcDir, o->fileListFiles->str, NULL, U_IS_BIG_ENDIAN ? 'b' : 'l');
    533         if (result != 0) {
    534             fprintf(stderr,"Error writing package dat file.\n");
    535             return result;
    536         }
    537 
    538         if (mode == MODE_COMMON) {
    539             char targetFileNamePath[LARGE_BUFFER_MAX_SIZE] = "";
    540 
    541             uprv_strcpy(targetFileNamePath, targetDir);
    542             uprv_strcat(targetFileNamePath, datFileName);
    543 
    544             if (T_FileStream_file_exists(targetFileNamePath)) {
    545                 if ((result = remove(targetFileNamePath)) != 0) {
    546                     fprintf(stderr, "Unable to remove old dat file: %s\n", targetFileNamePath);
    547                     return result;
    548                 }
    549             }
    550 
    551             /* Move the dat file created to the target directory. */
    552             result = rename(datFileNamePath, targetFileNamePath);
    553             if (result != 0) {
    554                 fprintf(stderr, "Unable to move dat file (%s) to target location (%s).\n", datFileNamePath, targetFileNamePath);
    555             }
    556 
    557             return result;
    558         } else /* if (mode[0] == MODE_STATIC || mode[0] == MODE_DLL) */ {
    559             char gencFilePath[SMALL_BUFFER_MAX_SIZE] = "";
    560             char version_major[10] = "";
    561             UBool reverseExt = FALSE;
    562 
    563 #ifndef WINDOWS_WITH_MSVC
    564             /* Get the version major number. */
    565             if (o->version != NULL) {
    566                 for (uint32_t i = 0;i < sizeof(version_major);i++) {
    567                     if (o->version[i] == '.') {
    568                         version_major[i] = 0;
    569                         break;
    570                     }
    571                     version_major[i] = o->version[i];
    572                 }
    573             }
    574 
    575 #ifndef OS400
    576             /* Certain platforms have different library extension ordering. (e.g. libicudata.##.so vs libicudata.so.##)
    577              * reverseExt is FALSE if the suffix should be the version number.
    578              */
    579             if (pkgDataFlags[LIB_EXT_ORDER][uprv_strlen(pkgDataFlags[LIB_EXT_ORDER])-1] == pkgDataFlags[SO_EXT][uprv_strlen(pkgDataFlags[SO_EXT])-1]) {
    580                 reverseExt = TRUE;
    581             }
    582 #endif
    583             /* Using the base libName and version number, generate the library file names. */
    584             createFileNames(version_major, o->version, o->libName, reverseExt);
    585 
    586             if (o->version != 0 && o->rebuild == FALSE) {
    587                 /* Check to see if a previous built data library file exists and check if it is the latest. */
    588                 sprintf(checkLibFile, "%s%s", targetDir, libFileNames[LIB_FILE_VERSION_TMP]);
    589                 if (T_FileStream_file_exists(checkLibFile)) {
    590                     if (isFileModTimeLater(checkLibFile, o->srcDir, TRUE) && isFileModTimeLater(checkLibFile, o->options)) {
    591                         if (o->install != NULL) {
    592                             uprv_strcpy(libFileNames[LIB_FILE_VERSION], libFileNames[LIB_FILE_VERSION_TMP]);
    593                             result = pkg_installLibrary(o->install, targetDir);
    594                         }
    595                         return result;
    596                     }
    597                 }
    598             }
    599 
    600             pkg_checkFlag(o);
    601 #endif
    602 
    603             if (pkgDataFlags[GENCCODE_ASSEMBLY_TYPE][0] != 0) {
    604                 const char* genccodeAssembly = pkgDataFlags[GENCCODE_ASSEMBLY_TYPE];
    605 
    606                 /* Offset genccodeAssembly by 3 because "-a " */
    607                 if (checkAssemblyHeaderName(genccodeAssembly+3)) {
    608                     writeAssemblyCode(datFileNamePath, o->tmpDir, o->entryName, NULL, gencFilePath);
    609 
    610                     result = pkg_createWithAssemblyCode(targetDir, mode, gencFilePath);
    611                     if (result != 0) {
    612                         fprintf(stderr, "Error generating assembly code for data.\n");
    613                         return result;
    614                     } else if (mode == MODE_STATIC) {
    615                         return result;
    616                     }
    617                 } else {
    618                     fprintf(stderr,"Assembly type \"%s\" is unknown.\n", genccodeAssembly);
    619                     return -1;
    620                 }
    621             } else {
    622 #ifdef CAN_WRITE_OBJ_CODE
    623                 writeObjectCode(datFileNamePath, o->tmpDir, o->entryName, NULL, NULL, gencFilePath);
    624 #ifdef U_LINUX
    625                 result = pkg_generateLibraryFile(targetDir, mode, gencFilePath);
    626 #elif defined(WINDOWS_WITH_MSVC)
    627                 return pkg_createWindowsDLL(mode, gencFilePath, o);
    628 #endif
    629 #elif defined(BUILD_DATA_WITHOUT_ASSEMBLY)
    630                 result = pkg_createWithoutAssemblyCode(o, targetDir, mode);
    631 #endif
    632                 if (result != 0) {
    633                     fprintf(stderr, "Error generating package data.\n");
    634                     return result;
    635                 }
    636             }
    637 #ifndef U_WINDOWS
    638             /* Certain platforms uses archive library. (e.g. AIX) */
    639             result = pkg_archiveLibrary(targetDir, o->version, reverseExt);
    640             if (result != 0) {
    641                 fprintf(stderr, "Error creating data archive library file.\n");
    642                return result;
    643             }
    644 #ifndef OS400
    645             /* Create symbolic links for the final library file. */
    646             result = pkg_createSymLinks(targetDir);
    647             if (result != 0) {
    648                 fprintf(stderr, "Error creating symbolic links of the data library file.\n");
    649                 return result;
    650             }
    651 #endif
    652             /* Install the libraries if option was set. */
    653             if (o->install != NULL) {
    654                 result = pkg_installLibrary(o->install, targetDir);
    655                 if (result != 0) {
    656                     fprintf(stderr, "Error installing the data library.\n");
    657                     return result;
    658                 }
    659             }
    660 #endif
    661         }
    662     }
    663     return result;
    664 }
    665 /*
    666  * Given the base libName and version numbers, generate the libary file names and store it in libFileNames.
    667  * Depending on the configuration, the library name may either end with version number or shared object suffix.
    668  */
    669 static void createFileNames(const char *version_major, const char *version, const char *libName, UBool reverseExt) {
    670         sprintf(libFileNames[LIB_FILE], "%s%s",
    671                 pkgDataFlags[LIBPREFIX],
    672                 libName);
    673         if (version != NULL) {
    674 #ifdef U_CYGWIN
    675             sprintf(libFileNames[LIB_FILE_CYGWIN], "cyg%s%s.%s",
    676                     libName,
    677                     version_major,
    678                     pkgDataFlags[SO_EXT]);
    679 
    680             sprintf(pkgDataFlags[SO_EXT], "%s.%s",
    681                     pkgDataFlags[SO_EXT],
    682                     pkgDataFlags[A_EXT]);
    683 #elif defined(OS400)
    684             sprintf(libFileNames[LIB_FILE_VERSION_TMP], "%s.%s",
    685                     libFileNames[LIB_FILE],
    686                     pkgDataFlags[SOBJ_EXT]);
    687 #else
    688             sprintf(libFileNames[LIB_FILE_VERSION_TMP], "%s%s%s.%s",
    689                     libFileNames[LIB_FILE],
    690                     pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "",
    691                     reverseExt ? version : pkgDataFlags[SOBJ_EXT],
    692                     reverseExt ? pkgDataFlags[SOBJ_EXT] : version);
    693 #endif
    694             sprintf(libFileNames[LIB_FILE_VERSION_MAJOR], "%s%s%s.%s",
    695                     libFileNames[LIB_FILE],
    696                     pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "",
    697                     reverseExt ? version_major : pkgDataFlags[SO_EXT],
    698                     reverseExt ? pkgDataFlags[SO_EXT] : version_major);
    699 
    700             libFileNames[LIB_FILE_VERSION][0] = 0;
    701 
    702 #ifdef U_CYGWIN
    703             /* Cygwin only deals with the version major number. */
    704             uprv_strcpy(libFileNames[LIB_FILE_VERSION_TMP], libFileNames[LIB_FILE_VERSION_MAJOR]);
    705 #endif
    706         }
    707 }
    708 
    709 /* Create the symbolic links for the final library file. */
    710 static int32_t pkg_createSymLinks(const char *targetDir) {
    711     int32_t result = 0;
    712     char cmd[LARGE_BUFFER_MAX_SIZE];
    713 
    714 #ifndef U_CYGWIN
    715     /* No symbolic link to make. */
    716     if (uprv_strlen(libFileNames[LIB_FILE_VERSION]) == 0 || uprv_strlen(libFileNames[LIB_FILE_VERSION_MAJOR]) == 0) {
    717         return result;
    718     }
    719 
    720     sprintf(cmd, "cd %s && %s %s && %s %s %s",
    721             targetDir,
    722             RM_CMD,
    723             libFileNames[LIB_FILE_VERSION_MAJOR],
    724             LN_CMD,
    725             libFileNames[LIB_FILE_VERSION],
    726             libFileNames[LIB_FILE_VERSION_MAJOR]);
    727     result = system(cmd);
    728     if (result != 0) {
    729         return result;
    730     }
    731 #endif
    732     sprintf(cmd, "cd %s && %s %s.%s && %s %s %s.%s",
    733             targetDir,
    734             RM_CMD,
    735             libFileNames[LIB_FILE], pkgDataFlags[SO_EXT],
    736             LN_CMD,
    737             libFileNames[LIB_FILE_VERSION],
    738             libFileNames[LIB_FILE], pkgDataFlags[SO_EXT]);
    739 
    740      result = system(cmd);
    741 
    742     return result;
    743 }
    744 
    745 static int32_t pkg_installLibrary(const char *installDir, const char *targetDir) {
    746     int32_t result = 0;
    747     char cmd[SMALL_BUFFER_MAX_SIZE];
    748 
    749     sprintf(cmd, "cd %s && %s %s %s%s%s",
    750             targetDir,
    751             pkgDataFlags[INSTALL_CMD],
    752             libFileNames[LIB_FILE_VERSION],
    753             installDir, PKGDATA_FILE_SEP_STRING, libFileNames[LIB_FILE_VERSION]
    754             );
    755 
    756     result = system(cmd);
    757 
    758     if (result != 0) {
    759         return result;
    760     }
    761 
    762     return pkg_createSymLinks(installDir);
    763 }
    764 
    765 #ifdef U_WINDOWS_MSVC
    766 /* Copy commands for installing the raw data files on Windows. */
    767 #define WIN_INSTALL_CMD "xcopy"
    768 #define WIN_INSTALL_CMD_FLAGS "/E /Y /K"
    769 #endif
    770 static int32_t pkg_installFileMode(const char *installDir, const char *srcDir, const char *fileListName) {
    771     int32_t result = 0;
    772     char cmd[SMALL_BUFFER_MAX_SIZE] = "";
    773 
    774     if (!T_FileStream_file_exists(installDir)) {
    775         UErrorCode status = U_ZERO_ERROR;
    776 
    777         uprv_mkdir(installDir, &status);
    778         if (U_FAILURE(status)) {
    779             fprintf(stderr, "Error creating installation directory: %s\n", installDir);
    780             return -1;
    781         }
    782     }
    783 #ifndef U_WINDOWS_WITH_MSVC
    784     char buffer[SMALL_BUFFER_MAX_SIZE] = "";
    785 
    786     FileStream *f = T_FileStream_open(fileListName, "r");
    787     if (f != NULL) {
    788         for(;;) {
    789             if (T_FileStream_readLine(f, buffer, SMALL_BUFFER_MAX_SIZE) != NULL) {
    790                 /* Remove new line character. */
    791                 buffer[uprv_strlen(buffer)-1] = 0;
    792 
    793                 sprintf(cmd, "%s %s%s%s %s%s%s",
    794                         pkgDataFlags[INSTALL_CMD],
    795                         srcDir, PKGDATA_FILE_SEP_STRING, buffer,
    796                         installDir, PKGDATA_FILE_SEP_STRING, buffer);
    797 
    798                 result = system(cmd);
    799                 if (result != 0) {
    800                     fprintf(stderr, "Failed to install data file with command: %s\n", cmd);
    801                     break;
    802                 }
    803             } else {
    804                 if (!T_FileStream_eof(f)) {
    805                     fprintf(stderr, "Failed to read line from file: %s\n", fileListName);
    806                     result = -1;
    807                 }
    808                 break;
    809             }
    810         }
    811         T_FileStream_close(f);
    812     } else {
    813         result = -1;
    814         fprintf(stderr, "Unable to open list file: %s\n", fileListName);
    815     }
    816 #else
    817     sprintf(cmd, "%s %s %s %s", WIN_INSTALL_CMD, srcDir, installDir, WIN_INSTALL_CMD_FLAGS);
    818     result = system(cmd);
    819     if (result != 0) {
    820         fprintf(stderr, "Failed to install data file with command: %s\n", cmd);
    821     }
    822 #endif
    823 
    824     return result;
    825 }
    826 
    827 /* Archiving of the library file may be needed depending on the platform and options given.
    828  * If archiving is not needed, copy over the library file name.
    829  */
    830 static int32_t pkg_archiveLibrary(const char *targetDir, const char *version, UBool reverseExt) {
    831     int32_t result = 0;
    832     char cmd[LARGE_BUFFER_MAX_SIZE];
    833 
    834     /* If the shard object suffix and the final object suffix is different and the final object suffix and the
    835      * archive file suffix is the same, then the final library needs to be archived.
    836      */
    837     if (uprv_strcmp(pkgDataFlags[SOBJ_EXT], pkgDataFlags[SO_EXT]) != 0 && uprv_strcmp(pkgDataFlags[A_EXT], pkgDataFlags[SO_EXT]) == 0) {
    838         sprintf(libFileNames[LIB_FILE_VERSION], "%s%s%s.%s",
    839                 libFileNames[LIB_FILE],
    840                 pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "",
    841                 reverseExt ? version : pkgDataFlags[SO_EXT],
    842                 reverseExt ? pkgDataFlags[SO_EXT] : version);
    843 
    844         sprintf(cmd, "%s %s %s%s %s%s",
    845                 pkgDataFlags[AR],
    846                 pkgDataFlags[ARFLAGS],
    847                 targetDir,
    848                 libFileNames[LIB_FILE_VERSION],
    849                 targetDir,
    850                 libFileNames[LIB_FILE_VERSION_TMP]);
    851 
    852         result = system(cmd);
    853         if (result != 0) {
    854             return result;
    855         }
    856 
    857         /* Remove unneeded library file. */
    858         sprintf(cmd, "%s %s%s",
    859                 RM_CMD,
    860                 targetDir,
    861                 libFileNames[LIB_FILE_VERSION_TMP]);
    862 
    863         result = system(cmd);
    864         if (result != 0) {
    865             return result;
    866         }
    867 
    868     } else {
    869         uprv_strcpy(libFileNames[LIB_FILE_VERSION], libFileNames[LIB_FILE_VERSION_TMP]);
    870     }
    871 
    872     return result;
    873 }
    874 
    875 /*
    876  * Using the compiler information from the configuration file set by -O option, generate the library file.
    877  * command may be given to allow for a larger buffer for cmd.
    878  */
    879 static int32_t pkg_generateLibraryFile(const char *targetDir, const char mode, const char *objectFile, char *command) {
    880     int32_t result = 0;
    881     char *cmd = NULL;
    882     UBool freeCmd = FALSE;
    883 
    884     /* This is necessary because if packaging is done without assembly code, objectFile might be extremely large
    885      * containing many object files and so the calling function should supply a command buffer that is large
    886      * enough to handle this. Otherwise, use the default size.
    887      */
    888     if (command != NULL) {
    889         cmd = command;
    890     } else {
    891         if ((cmd = (char *)uprv_malloc(sizeof(char) * LARGE_BUFFER_MAX_SIZE)) == NULL) {
    892             fprintf(stderr, "Unable to allocate memory for command.\n");
    893             return -1;
    894         }
    895         freeCmd = TRUE;
    896     }
    897 
    898     if (mode == MODE_STATIC) {
    899 #ifdef OS400
    900         sprintf(cmd, "QSH CMD('%s %s %s%s.%s %s')",
    901 #else
    902         sprintf(cmd, "%s %s %s%s.%s %s",
    903 #endif
    904                 pkgDataFlags[AR],
    905                 pkgDataFlags[ARFLAGS],
    906                 targetDir,
    907                 libFileNames[LIB_FILE],
    908                 pkgDataFlags[A_EXT],
    909                 objectFile);
    910 
    911         result = system(cmd);
    912     } else /* if (mode == MODE_DLL) */ {
    913 #ifdef U_CYGWIN
    914         sprintf(cmd, "%s%s%s %s -o %s%s %s %s%s %s %s",
    915                 pkgDataFlags[GENLIB],
    916                 targetDir,
    917                 libFileNames[LIB_FILE_VERSION_TMP],
    918                 pkgDataFlags[LDICUDTFLAGS],
    919                 targetDir, libFileNames[LIB_FILE_CYGWIN],
    920 #else
    921 #ifdef OS400
    922         sprintf(cmd, "QSH CMD('%s %s -o %s%s %s %s%s %s %s')",
    923 #else
    924         sprintf(cmd, "%s %s -o %s%s %s %s%s %s %s",
    925 #endif
    926                 pkgDataFlags[GENLIB],
    927                 pkgDataFlags[LDICUDTFLAGS],
    928                 targetDir,
    929                 libFileNames[LIB_FILE_VERSION_TMP],
    930 #endif
    931                 objectFile,
    932                 pkgDataFlags[LD_SONAME],
    933                 pkgDataFlags[LD_SONAME][0] == 0 ? "" : libFileNames[LIB_FILE_VERSION_MAJOR],
    934                 pkgDataFlags[RPATH_FLAGS],
    935                 pkgDataFlags[BIR_FLAGS]);
    936 
    937         /* Generate the library file. */
    938         result = system(cmd);
    939     }
    940 
    941     if (freeCmd) {
    942         uprv_free(cmd);
    943     }
    944 
    945     return result;
    946 }
    947 
    948 static int32_t pkg_createWithAssemblyCode(const char *targetDir, const char mode, const char *gencFilePath) {
    949     char tempObjectFile[SMALL_BUFFER_MAX_SIZE] = "";
    950     char cmd[LARGE_BUFFER_MAX_SIZE] = "";
    951     int32_t result = 0;
    952 
    953     /* Remove the ending .s and replace it with .o for the new object file. */
    954     uprv_strcpy(tempObjectFile, gencFilePath);
    955     tempObjectFile[uprv_strlen(tempObjectFile)-1] = 'o';
    956 
    957     /* Generate the object file. */
    958     sprintf(cmd, "%s %s -o %s %s",
    959             pkgDataFlags[COMPILER],
    960             pkgDataFlags[LIBFLAGS],
    961             tempObjectFile,
    962             gencFilePath);
    963 
    964     result = system(cmd);
    965     if (result != 0) {
    966         return result;
    967     }
    968 
    969     return pkg_generateLibraryFile(targetDir, mode, tempObjectFile);
    970 }
    971 
    972 #ifdef BUILD_DATA_WITHOUT_ASSEMBLY
    973 /*
    974  * Generation of the data library without assembly code needs to compile each data file
    975  * individually and then link it all together.
    976  */
    977 enum {
    978     DATA_PREFIX_BRKITR,
    979     DATA_PREFIX_COLL,
    980     DATA_PREFIX_RBNF,
    981     DATA_PREFIX_TRANSLIT,
    982     DATA_PREFIX_LENGTH
    983 };
    984 const static char DATA_PREFIX[DATA_PREFIX_LENGTH][10] = {
    985         "brkitr",
    986         "coll",
    987         "rbnf",
    988         "translit"
    989 };
    990 static int32_t pkg_createWithoutAssemblyCode(UPKGOptions *o, const char *targetDir, const char mode) {
    991     int32_t result = 0;
    992     CharList *list = o->filePaths;
    993     CharList *listNames = o->files;
    994     int32_t listSize = pkg_countCharList(list);
    995     char *buffer;
    996     char *cmd;
    997     char gencmnFile[SMALL_BUFFER_MAX_SIZE] = "";
    998     char tempObjectFile[SMALL_BUFFER_MAX_SIZE] = "";
    999 #ifdef USE_SINGLE_CCODE_FILE
   1000     char icudtAll[SMALL_BUFFER_MAX_SIZE] = "";
   1001 
   1002     sprintf(icudtAll, "%s%s%sall.c",
   1003             o->tmpDir,
   1004             PKGDATA_FILE_SEP_STRING,
   1005             libFileNames[LIB_FILE]);
   1006 #endif
   1007 
   1008     if (list == NULL || listNames == NULL) {
   1009         /* list and listNames should never be NULL since we are looping through the CharList with
   1010          * the given size.
   1011          */
   1012         return -1;
   1013     }
   1014 
   1015     if ((cmd = (char *)uprv_malloc((listSize + 2) * SMALL_BUFFER_MAX_SIZE)) == NULL) {
   1016         fprintf(stderr, "Unable to allocate memory for cmd.\n");
   1017         return -1;
   1018     } else if ((buffer = (char *)uprv_malloc((listSize + 1) * SMALL_BUFFER_MAX_SIZE)) == NULL) {
   1019         fprintf(stderr, "Unable to allocate memory for buffer.\n");
   1020         uprv_free(cmd);
   1021         return -1;
   1022     }
   1023 
   1024     for (int32_t i = 0; i < (listSize + 1); i++) {
   1025         const char *file ;
   1026         const char *name;
   1027 
   1028         if (i == 0) {
   1029             /* The first iteration calls the gencmn function and initailizes the buffer. */
   1030             createCommonDataFile(o->tmpDir, o->shortName, o->entryName, NULL, o->srcDir, o->comment, o->fileListFiles->str, 0, TRUE, o->verbose, gencmnFile);
   1031             buffer[0] = 0;
   1032 #ifdef USE_SINGLE_CCODE_FILE
   1033             uprv_strcpy(tempObjectFile, gencmnFile);
   1034             tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
   1035 
   1036 #ifdef OS400
   1037             sprintf(cmd, "QSH CMD('%s %s -o %s %s')",
   1038 #else
   1039             sprintf(cmd, "%s %s -o %s %s"
   1040 #endif
   1041                         pkgDataFlags[COMPILER],
   1042                         pkgDataFlags[LIBFLAGS],
   1043                         tempObjectFile,
   1044                         gencmnFile);
   1045 
   1046             result = system(cmd);
   1047             if (result != 0) {
   1048                 break;
   1049             }
   1050 
   1051             sprintf(buffer, "%s",tempObjectFile);
   1052 #endif
   1053         } else {
   1054             char newName[SMALL_BUFFER_MAX_SIZE];
   1055             char dataName[SMALL_BUFFER_MAX_SIZE];
   1056             const char *pSubstring;
   1057             file = list->str;
   1058             name = listNames->str;
   1059 
   1060             newName[0] = dataName[0] = 0;
   1061             for (int32_t n = 0; n < DATA_PREFIX_LENGTH; n++) {
   1062                 /* If the name contains a prefix, alter the new name accordingly. */
   1063                 pSubstring = uprv_strstr(name, DATA_PREFIX[n]);
   1064                 if (pSubstring != NULL) {
   1065                     char newNameTmp[SMALL_BUFFER_MAX_SIZE] = "";
   1066                     const char *p = name + uprv_strlen(DATA_PREFIX[n]) + 1;
   1067                     for (int32_t i = 0;;i++) {
   1068                         if (p[i] == '.') {
   1069                             newNameTmp[i] = '_';
   1070                             continue;
   1071                         }
   1072                         newNameTmp[i] = p[i];
   1073                         if (p[i] == 0) {
   1074                             break;
   1075                         }
   1076                     }
   1077                     sprintf(newName, "%s_%s",
   1078                             DATA_PREFIX[n],
   1079                             newNameTmp);
   1080                     sprintf(dataName, "%s_%s",
   1081                             o->shortName,
   1082                             DATA_PREFIX[n]);
   1083                 }
   1084                 if (newName[0] != 0) {
   1085                     break;
   1086                 }
   1087             }
   1088 
   1089             writeCCode(file, o->tmpDir, dataName[0] != 0 ? dataName : o->shortName, newName[0] != 0 ? newName : NULL, gencmnFile);
   1090 #ifdef USE_SINGLE_CCODE_FILE
   1091 #ifdef OS400
   1092             sprintf(cmd, "QSH CMD('cat %s >> %s')", gencmnFile, icudtAll);
   1093 #else
   1094             sprintf(cmd, "cat %s >> %s", gencmnFile, icudtAll);
   1095 #endif
   1096 
   1097             result = system(cmd);
   1098             if (result != 0) {
   1099                 break;
   1100             }
   1101 #endif
   1102         }
   1103 
   1104 #ifndef USE_SINGLE_CCODE_FILE
   1105         uprv_strcpy(tempObjectFile, gencmnFile);
   1106         tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
   1107 
   1108         sprintf(cmd, "%s %s -o %s %s",
   1109                     pkgDataFlags[COMPILER],
   1110                     pkgDataFlags[LIBFLAGS],
   1111                     tempObjectFile,
   1112                     gencmnFile);
   1113         result = system(cmd);
   1114         if (result != 0) {
   1115             break;
   1116         }
   1117 
   1118         sprintf(buffer, "%s %s",
   1119                 buffer,
   1120                 tempObjectFile);
   1121 #endif
   1122 
   1123         if (i > 0) {
   1124             list = list->next;
   1125             listNames = listNames->next;
   1126         }
   1127     }
   1128 
   1129 #ifdef USE_SINGLE_CCODE_FILE
   1130     uprv_strcpy(tempObjectFile, icudtAll);
   1131     tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
   1132 #ifdef OS400
   1133     sprintf(cmd, "QSH CMD('%s %s -o %s %s')",
   1134 #else
   1135     sprintf(cmd, "%s %s -o %s %s",
   1136 #endif
   1137         pkgDataFlags[COMPILER],
   1138         pkgDataFlags[LIBFLAGS],
   1139         tempObjectFile,
   1140         icudtAll);
   1141 
   1142     result = system(cmd);
   1143     if (result == 0) {
   1144         sprintf(buffer, "%s %s",
   1145             buffer,
   1146             tempObjectFile);
   1147     }
   1148 #endif
   1149 
   1150     if (result == 0) {
   1151         /* Generate the library file. */
   1152         result = pkg_generateLibraryFile(targetDir, mode, buffer, cmd);
   1153     }
   1154     uprv_free(buffer);
   1155     uprv_free(cmd);
   1156 
   1157     return result;
   1158 }
   1159 #endif
   1160 
   1161 #ifdef WINDOWS_WITH_MSVC
   1162 #define LINK_CMD "link.exe /nologo /release /out:"
   1163 #define LINK_FLAGS "/DLL /NOENTRY /MANIFEST:NO  /base:0x4ad00000 /implib:"
   1164 #define LIB_CMD "LIB.exe /nologo /out:"
   1165 #define LIB_FILE "icudt.lib"
   1166 #define LIB_EXT UDATA_LIB_SUFFIX
   1167 #define DLL_EXT UDATA_SO_SUFFIX
   1168 
   1169 static int32_t pkg_createWindowsDLL(const char mode, const char *gencFilePath, UPKGOptions *o) {
   1170     char cmd[LARGE_BUFFER_MAX_SIZE];
   1171     if (mode == MODE_STATIC) {
   1172         char staticLibFilePath[SMALL_BUFFER_MAX_SIZE] = "";
   1173 
   1174         uprv_strcpy(staticLibFilePath, o->tmpDir);
   1175         uprv_strcat(staticLibFilePath, PKGDATA_FILE_SEP_STRING);
   1176 
   1177         uprv_strcat(staticLibFilePath, o->entryName);
   1178         uprv_strcat(staticLibFilePath, LIB_EXT);
   1179 
   1180         sprintf(cmd, "%s\"%s\" \"%s\"",
   1181                 LIB_CMD,
   1182                 staticLibFilePath,
   1183                 gencFilePath);
   1184     } else if (mode == MODE_DLL) {
   1185         char dllFilePath[SMALL_BUFFER_MAX_SIZE] = "";
   1186         char libFilePath[SMALL_BUFFER_MAX_SIZE] = "";
   1187         char resFilePath[SMALL_BUFFER_MAX_SIZE] = "";
   1188 
   1189 #ifdef CYGWINMSVC
   1190         uprv_strcpy(dllFilePath, o->targetDir);
   1191 #else
   1192         uprv_strcpy(dllFilePath, o->srcDir);
   1193 #endif
   1194         uprv_strcat(dllFilePath, PKGDATA_FILE_SEP_STRING);
   1195         uprv_strcpy(libFilePath, dllFilePath);
   1196 
   1197         uprv_strcpy(resFilePath, o->tmpDir);
   1198         uprv_strcat(resFilePath, PKGDATA_FILE_SEP_STRING);
   1199 
   1200         uprv_strcat(dllFilePath, o->entryName);
   1201         uprv_strcat(dllFilePath, DLL_EXT);
   1202         uprv_strcat(libFilePath, LIB_FILE);
   1203         uprv_strcat(resFilePath, ICUDATA_RES_FILE);
   1204 
   1205         if (!T_FileStream_file_exists(resFilePath)) {
   1206             uprv_memset(resFilePath, 0, sizeof(resFilePath));
   1207         }
   1208 
   1209         /* Check if dll file and lib file exists and that it is not newer than genc file. */
   1210         if (!o->rebuild && (T_FileStream_file_exists(dllFilePath) && isFileModTimeLater(dllFilePath, gencFilePath)) &&
   1211             (T_FileStream_file_exists(libFilePath) && isFileModTimeLater(libFilePath, gencFilePath))) {
   1212             return 0;
   1213         }
   1214 
   1215         sprintf(cmd, "%s\"%s\" %s\"%s\" \"%s\" \"%s\"",
   1216                 LINK_CMD,
   1217                 dllFilePath,
   1218                 LINK_FLAGS,
   1219                 libFilePath,
   1220                 gencFilePath,
   1221                 resFilePath
   1222                 );
   1223     }
   1224 
   1225     return system(cmd);
   1226 }
   1227 #endif
   1228 
   1229 static void pkg_checkFlag(UPKGOptions *o) {
   1230 #ifdef U_AIX
   1231     /* AIX needs a map file. */
   1232     char *flag = NULL;
   1233     int32_t length = 0;
   1234     char tmpbuffer[SMALL_BUFFER_MAX_SIZE];
   1235     const char MAP_FILE_EXT[] = ".map";
   1236     FileStream *f = NULL;
   1237     char mapFile[SMALL_BUFFER_MAX_SIZE] = "";
   1238     int32_t start = -1;
   1239     int32_t count = 0;
   1240 
   1241     flag = pkgDataFlags[BIR_FLAGS];
   1242     length = uprv_strlen(pkgDataFlags[BIR_FLAGS]);
   1243 
   1244     for (int32_t i = 0; i < length; i++) {
   1245         if (flag[i] == MAP_FILE_EXT[count]) {
   1246             if (count == 0) {
   1247                 start = i;
   1248             }
   1249             count++;
   1250         } else {
   1251             count = 0;
   1252         }
   1253 
   1254         if (count == uprv_strlen(MAP_FILE_EXT)) {
   1255             break;
   1256         }
   1257     }
   1258 
   1259     if (start >= 0) {
   1260         int32_t index = 0;
   1261         for (int32_t i = 0;;i++) {
   1262             if (i == start) {
   1263                 for (int32_t n = 0;;n++) {
   1264                     if (o->shortName[n] == 0) {
   1265                         break;
   1266                     }
   1267                     tmpbuffer[index++] = o->shortName[n];
   1268                 }
   1269             }
   1270 
   1271             tmpbuffer[index++] = flag[i];
   1272 
   1273             if (flag[i] == 0) {
   1274                 break;
   1275             }
   1276         }
   1277 
   1278         uprv_memset(flag, 0, length);
   1279         uprv_strcpy(flag, tmpbuffer);
   1280 
   1281         uprv_strcpy(mapFile, o->shortName);
   1282         uprv_strcat(mapFile, MAP_FILE_EXT);
   1283 
   1284         f = T_FileStream_open(mapFile, "w");
   1285         if (f == NULL) {
   1286             fprintf(stderr,"Unable to create map file: %s.\n", mapFile);
   1287             return;
   1288         }
   1289 
   1290         sprintf(tmpbuffer, "%s%s ", o->entryName, UDATA_CMN_INTERMEDIATE_SUFFIX);
   1291 
   1292         T_FileStream_writeLine(f, tmpbuffer);
   1293 
   1294         T_FileStream_close(f);
   1295     }
   1296 #elif defined(U_CYGWIN)
   1297     /* Cygwin needs to change flag options. */
   1298     char *flag = NULL;
   1299     int32_t length = 0;
   1300 
   1301     flag = pkgDataFlags[GENLIB];
   1302     length = uprv_strlen(pkgDataFlags[GENLIB]);
   1303 
   1304     int32_t position = length - 1;
   1305 
   1306     for(;position >= 0;position--) {
   1307         if (flag[position] == '=') {
   1308             position++;
   1309             break;
   1310         }
   1311     }
   1312 
   1313     uprv_memset(flag + position, 0, length - position);
   1314 #elif defined(OS400)
   1315     /* OS400 needs to fix the ld options (swap single quote with double quote) */
   1316     char *flag = NULL;
   1317     int32_t length = 0;
   1318 
   1319     flag = pkgDataFlags[GENLIB];
   1320     length = uprv_strlen(pkgDataFlags[GENLIB]);
   1321 
   1322     int32_t position = length - 1;
   1323 
   1324     for(int32_t i = 0; i < length; i++) {
   1325         if (flag[i] == '\'') {
   1326             flag[i] = '\"';
   1327         }
   1328     }
   1329 #endif
   1330 }
   1331 
   1332 static void loadLists(UPKGOptions *o, UErrorCode *status)
   1333 {
   1334     CharList   *l, *tail = NULL, *tail2 = NULL;
   1335     FileStream *in;
   1336     char        line[16384];
   1337     char       *linePtr, *lineNext;
   1338     const uint32_t   lineMax = 16300;
   1339     char        tmp[1024];
   1340     char       *s;
   1341     int32_t     ln=0; /* line number */
   1342 
   1343     for(l = o->fileListFiles; l; l = l->next) {
   1344         if(o->verbose) {
   1345             fprintf(stdout, "# Reading %s..\n", l->str);
   1346         }
   1347         /* TODO: stdin */
   1348         in = T_FileStream_open(l->str, "r"); /* open files list */
   1349 
   1350         if(!in) {
   1351             fprintf(stderr, "Error opening <%s>.\n", l->str);
   1352             *status = U_FILE_ACCESS_ERROR;
   1353             return;
   1354         }
   1355 
   1356         while(T_FileStream_readLine(in, line, sizeof(line))!=NULL) { /* for each line */
   1357             ln++;
   1358             if(uprv_strlen(line)>lineMax) {
   1359                 fprintf(stderr, "%s:%d - line too long (over %d chars)\n", l->str, (int)ln, (int)lineMax);
   1360                 exit(1);
   1361             }
   1362             /* remove spaces at the beginning */
   1363             linePtr = line;
   1364             while(isspace(*linePtr)) {
   1365                 linePtr++;
   1366             }
   1367             s=linePtr;
   1368             /* remove trailing newline characters */
   1369             while(*s!=0) {
   1370                 if(*s=='\r' || *s=='\n') {
   1371                     *s=0;
   1372                     break;
   1373                 }
   1374                 ++s;
   1375             }
   1376             if((*linePtr == 0) || (*linePtr == '#')) {
   1377                 continue; /* comment or empty line */
   1378             }
   1379 
   1380             /* Now, process the line */
   1381             lineNext = NULL;
   1382 
   1383             while(linePtr && *linePtr) { /* process space-separated items */
   1384                 while(*linePtr == ' ') {
   1385                     linePtr++;
   1386                 }
   1387                 /* Find the next quote */
   1388                 if(linePtr[0] == '"')
   1389                 {
   1390                     lineNext = uprv_strchr(linePtr+1, '"');
   1391                     if(lineNext == NULL) {
   1392                         fprintf(stderr, "%s:%d - missing trailing double quote (\")\n",
   1393                             l->str, (int)ln);
   1394                         exit(1);
   1395                     } else {
   1396                         lineNext++;
   1397                         if(*lineNext) {
   1398                             if(*lineNext != ' ') {
   1399                                 fprintf(stderr, "%s:%d - malformed quoted line at position %d, expected ' ' got '%c'\n",
   1400                                     l->str, (int)ln, (int)(lineNext-line), (*lineNext)?*lineNext:'0');
   1401                                 exit(1);
   1402                             }
   1403                             *lineNext = 0;
   1404                             lineNext++;
   1405                         }
   1406                     }
   1407                 } else {
   1408                     lineNext = uprv_strchr(linePtr, ' ');
   1409                     if(lineNext) {
   1410                         *lineNext = 0; /* terminate at space */
   1411                         lineNext++;
   1412                     }
   1413                 }
   1414 
   1415                 /* add the file */
   1416                 s = (char*)getLongPathname(linePtr);
   1417 
   1418                 /* normal mode.. o->files is just the bare list without package names */
   1419                 o->files = pkg_appendToList(o->files, &tail, uprv_strdup(linePtr));
   1420                 if(uprv_pathIsAbsolute(s)) {
   1421                     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);
   1422                     exit(U_ILLEGAL_ARGUMENT_ERROR);
   1423                 }
   1424                 uprv_strcpy(tmp, o->srcDir);
   1425                 uprv_strcat(tmp, o->srcDir[uprv_strlen(o->srcDir)-1] == U_FILE_SEP_CHAR ? "" :PKGDATA_FILE_SEP_STRING);
   1426                 uprv_strcat(tmp, s);
   1427                 o->filePaths = pkg_appendToList(o->filePaths, &tail2, uprv_strdup(tmp));
   1428                 linePtr = lineNext;
   1429             } /* for each entry on line */
   1430         } /* for each line */
   1431         T_FileStream_close(in);
   1432     } /* for each file list file */
   1433 }
   1434 
   1435 /* Try calling icu-config directly to get the option file. */
   1436 static int32_t pkg_getOptionsFromICUConfig(UOption *option) {
   1437 #if U_HAVE_POPEN
   1438     FILE *p;
   1439     size_t n;
   1440     static char buf[512] = "";
   1441     const char cmd[] = "icu-config --incpkgdatafile";
   1442 
   1443     p = popen(cmd, "r");
   1444 
   1445     if(p == NULL)
   1446     {
   1447         fprintf(stderr, "%s: icu-config: No icu-config found. (fix PATH or use -O option)\n", progname);
   1448         return -1;
   1449     }
   1450 
   1451     n = fread(buf, 1, 511, p);
   1452 
   1453     pclose(p);
   1454 
   1455     if(n<=0)
   1456     {
   1457         fprintf(stderr,"%s: icu-config: Could not read from icu-config. (fix PATH or use -O option)\n", progname);
   1458         return -1;
   1459     }
   1460 
   1461     for (int32_t length = strlen(buf) - 1; length >= 0; length--) {
   1462         if (buf[length] == '\n' || buf[length] == ' ') {
   1463             buf[length] = 0;
   1464         } else {
   1465             break;
   1466         }
   1467     }
   1468 
   1469     if(buf[strlen(buf)-1]=='\n')
   1470     {
   1471         buf[strlen(buf)-1]=0;
   1472     }
   1473 
   1474     if(buf[0] == 0)
   1475     {
   1476         fprintf(stderr, "%s: icu-config: invalid response from icu-config (fix PATH or use -O option)\n", progname);
   1477         return -1;
   1478     }
   1479 
   1480     option->value = buf;
   1481     option->doesOccur = TRUE;
   1482 
   1483     return 0;
   1484 #endif
   1485     return -1;
   1486 }
   1487