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