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