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 static int32_t pkg_installCommonMode(const char *installDir, const char *fileName);
    114 
    115 #ifdef BUILD_DATA_WITHOUT_ASSEMBLY
    116 static int32_t pkg_createWithoutAssemblyCode(UPKGOptions *o, const char *targetDir, const char mode);
    117 #endif
    118 
    119 static int32_t pkg_createWithAssemblyCode(const char *targetDir, const char mode, const char *gencFilePath);
    120 static int32_t pkg_generateLibraryFile(const char *targetDir, const char mode, const char *objectFile, char *command = NULL);
    121 static int32_t pkg_archiveLibrary(const char *targetDir, const char *version, UBool reverseExt);
    122 static void createFileNames(UPKGOptions *o, const char mode, const char *version_major, const char *version, const char *libName, const UBool reverseExt);
    123 static int32_t initializePkgDataFlags(UPKGOptions *o);
    124 
    125 static int32_t pkg_getOptionsFromICUConfig(UBool verbose, UOption *option);
    126 static int runCommand(const char* command, UBool specialHandling=FALSE);
    127 
    128 enum {
    129     NAME,
    130     BLDOPT,
    131     MODE,
    132     HELP,
    133     HELP_QUESTION_MARK,
    134     VERBOSE,
    135     COPYRIGHT,
    136     COMMENT,
    137     DESTDIR,
    138     REBUILD,
    139     TEMPDIR,
    140     INSTALL,
    141     SOURCEDIR,
    142     ENTRYPOINT,
    143     REVISION,
    144     FORCE_PREFIX,
    145     LIBNAME,
    146     QUIET
    147 };
    148 
    149 /* This sets the modes that are available */
    150 static struct {
    151     const char *name, *alt_name;
    152     const char *desc;
    153 } modes[] = {
    154         { "files", 0,           "Uses raw data files (no effect). Installation copies all files to the target location." },
    155 #ifdef U_WINDOWS
    156         { "dll",    "library",  "Generates one common data file and one shared library, <package>.dll"},
    157         { "common", "archive",  "Generates just the common file, <package>.dat"},
    158         { "static", "static",   "Generates one statically linked library, " LIB_PREFIX "<package>" UDATA_LIB_SUFFIX }
    159 #else
    160 #ifdef UDATA_SO_SUFFIX
    161         { "dll",    "library",  "Generates one shared library, <package>" UDATA_SO_SUFFIX },
    162 #endif
    163         { "common", "archive",  "Generates one common data file, <package>.dat" },
    164         { "static", "static",   "Generates one statically linked library, " LIB_PREFIX "<package>" UDATA_LIB_SUFFIX }
    165 #endif
    166 };
    167 
    168 static UOption options[]={
    169     /*00*/    UOPTION_DEF( "name",    'p', UOPT_REQUIRES_ARG),
    170     /*01*/    UOPTION_DEF( "bldopt",  'O', UOPT_REQUIRES_ARG), /* on Win32 it is release or debug */
    171     /*02*/    UOPTION_DEF( "mode",    'm', UOPT_REQUIRES_ARG),
    172     /*03*/    UOPTION_HELP_H,                                   /* -h */
    173     /*04*/    UOPTION_HELP_QUESTION_MARK,                       /* -? */
    174     /*05*/    UOPTION_VERBOSE,                                  /* -v */
    175     /*06*/    UOPTION_COPYRIGHT,                                /* -c */
    176     /*07*/    UOPTION_DEF( "comment", 'C', UOPT_REQUIRES_ARG),
    177     /*08*/    UOPTION_DESTDIR,                                  /* -d */
    178     /*11*/    UOPTION_DEF( "rebuild", 'F', UOPT_NO_ARG),
    179     /*12*/    UOPTION_DEF( "tempdir", 'T', UOPT_REQUIRES_ARG),
    180     /*13*/    UOPTION_DEF( "install", 'I', UOPT_REQUIRES_ARG),
    181     /*14*/    UOPTION_SOURCEDIR ,
    182     /*15*/    UOPTION_DEF( "entrypoint", 'e', UOPT_REQUIRES_ARG),
    183     /*16*/    UOPTION_DEF( "revision", 'r', UOPT_REQUIRES_ARG),
    184     /*17*/    UOPTION_DEF( "force-prefix", 'f', UOPT_NO_ARG),
    185     /*18*/    UOPTION_DEF( "libname", 'L', UOPT_REQUIRES_ARG),
    186     /*19*/    UOPTION_DEF( "quiet", 'q', UOPT_NO_ARG)
    187 };
    188 
    189 enum {
    190     GENCCODE_ASSEMBLY_TYPE,
    191     SO_EXT,
    192     SOBJ_EXT,
    193     A_EXT,
    194     LIBPREFIX,
    195     LIB_EXT_ORDER,
    196     COMPILER,
    197     LIBFLAGS,
    198     GENLIB,
    199     LDICUDTFLAGS,
    200     LD_SONAME,
    201     RPATH_FLAGS,
    202     BIR_FLAGS,
    203     AR,
    204     ARFLAGS,
    205     RANLIB,
    206     INSTALL_CMD,
    207     PKGDATA_FLAGS_SIZE
    208 };
    209 static char **pkgDataFlags = NULL;
    210 
    211 enum {
    212     LIB_FILE,
    213     LIB_FILE_VERSION_MAJOR,
    214     LIB_FILE_VERSION,
    215     LIB_FILE_VERSION_TMP,
    216 #ifdef U_CYGWIN
    217     LIB_FILE_CYGWIN,
    218 	LIB_FILE_CYGWIN_VERSION,
    219 #endif
    220     LIB_FILENAMES_SIZE
    221 };
    222 static char libFileNames[LIB_FILENAMES_SIZE][256];
    223 
    224 static UPKGOptions  *pkg_checkFlag(UPKGOptions *o);
    225 
    226 const char options_help[][320]={
    227     "Set the data name",
    228 #ifdef U_MAKE_IS_NMAKE
    229     "The directory where the ICU is located (e.g. <ICUROOT> which contains the bin directory)",
    230 #else
    231     "Specify options for the builder.",
    232 #endif
    233     "Specify the mode of building (see below; default: common)",
    234     "This usage text",
    235     "This usage text",
    236     "Make the output verbose",
    237     "Use the standard ICU copyright",
    238     "Use a custom comment (instead of the copyright)",
    239     "Specify the destination directory for files",
    240     "Force rebuilding of all data",
    241     "Specify temporary dir (default: output dir)",
    242     "Install the data (specify target)",
    243     "Specify a custom source directory",
    244     "Specify a custom entrypoint name (default: short name)",
    245     "Specify a version when packaging in dll or static mode",
    246     "Add package to all file names if not present",
    247     "Library name to build (if different than package name)",
    248     "Quite mode. (e.g. Do not output a readme file for static libraries)"
    249 };
    250 
    251 const char  *progname = "PKGDATA";
    252 
    253 int
    254 main(int argc, char* argv[]) {
    255     int result = 0;
    256     /* FileStream  *out; */
    257     UPKGOptions  o;
    258     CharList    *tail;
    259     UBool        needsHelp = FALSE;
    260     UErrorCode   status = U_ZERO_ERROR;
    261     /* char         tmp[1024]; */
    262     uint32_t i;
    263     int32_t n;
    264 
    265     U_MAIN_INIT_ARGS(argc, argv);
    266 
    267     progname = argv[0];
    268 
    269     options[MODE].value = "common";
    270 
    271     /* read command line options */
    272     argc=u_parseArgs(argc, argv, sizeof(options)/sizeof(options[0]), options);
    273 
    274     /* error handling, printing usage message */
    275     /* I've decided to simply print an error and quit. This tool has too
    276     many options to just display them all of the time. */
    277 
    278     if(options[HELP].doesOccur || options[HELP_QUESTION_MARK].doesOccur) {
    279         needsHelp = TRUE;
    280     }
    281     else {
    282         if(!needsHelp && argc<0) {
    283             fprintf(stderr,
    284                 "%s: error in command line argument \"%s\"\n",
    285                 progname,
    286                 argv[-argc]);
    287             fprintf(stderr, "Run '%s --help' for help.\n", progname);
    288             return 1;
    289         }
    290 
    291 
    292 #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN)
    293         if(!options[BLDOPT].doesOccur && uprv_strcmp(options[MODE].value, "common") != 0) {
    294           if (pkg_getOptionsFromICUConfig(options[VERBOSE].doesOccur, &options[BLDOPT]) != 0) {
    295                 fprintf(stderr, " required parameter is missing: -O is required for static and shared builds.\n");
    296                 fprintf(stderr, "Run '%s --help' for help.\n", progname);
    297                 return 1;
    298             }
    299         }
    300 #else
    301         if(options[BLDOPT].doesOccur) {
    302             fprintf(stdout, "Warning: You are using the -O option which is not needed for MSVC build on Windows.\n");
    303         }
    304 #endif
    305 
    306         if(!options[NAME].doesOccur) /* -O we already have - don't report it. */
    307         {
    308             fprintf(stderr, " required parameter -p is missing \n");
    309             fprintf(stderr, "Run '%s --help' for help.\n", progname);
    310             return 1;
    311         }
    312 
    313         if(argc == 1) {
    314             fprintf(stderr,
    315                 "No input files specified.\n"
    316                 "Run '%s --help' for help.\n", progname);
    317             return 1;
    318         }
    319     }   /* end !needsHelp */
    320 
    321     if(argc<0 || needsHelp  ) {
    322         fprintf(stderr,
    323             "usage: %s [-options] [-] [packageFile] \n"
    324             "\tProduce packaged ICU data from the given list(s) of files.\n"
    325             "\t'-' by itself means to read from stdin.\n"
    326             "\tpackageFile is a text file containing the list of files to package.\n",
    327             progname);
    328 
    329         fprintf(stderr, "\n options:\n");
    330         for(i=0;i<(sizeof(options)/sizeof(options[0]));i++) {
    331             fprintf(stderr, "%-5s -%c %s%-10s  %s\n",
    332                 (i<1?"[REQ]":""),
    333                 options[i].shortName,
    334                 options[i].longName ? "or --" : "     ",
    335                 options[i].longName ? options[i].longName : "",
    336                 options_help[i]);
    337         }
    338 
    339         fprintf(stderr, "modes: (-m option)\n");
    340         for(i=0;i<(sizeof(modes)/sizeof(modes[0]));i++) {
    341             fprintf(stderr, "   %-9s ", modes[i].name);
    342             if (modes[i].alt_name) {
    343                 fprintf(stderr, "/ %-9s", modes[i].alt_name);
    344             } else {
    345                 fprintf(stderr, "           ");
    346             }
    347             fprintf(stderr, "  %s\n", modes[i].desc);
    348         }
    349         return 1;
    350     }
    351 
    352     /* OK, fill in the options struct */
    353     uprv_memset(&o, 0, sizeof(o));
    354 
    355     o.mode      = options[MODE].value;
    356     o.version   = options[REVISION].doesOccur ? options[REVISION].value : 0;
    357 
    358     o.shortName = options[NAME].value;
    359     {
    360         int32_t len = (int32_t)uprv_strlen(o.shortName);
    361         char *csname, *cp;
    362         const char *sp;
    363 
    364         cp = csname = (char *) uprv_malloc((len + 1 + 1) * sizeof(*o.cShortName));
    365         if (*(sp = o.shortName)) {
    366             *cp++ = isalpha(*sp) ? * sp : '_';
    367             for (++sp; *sp; ++sp) {
    368                 *cp++ = isalnum(*sp) ? *sp : '_';
    369             }
    370         }
    371         *cp = 0;
    372 
    373         o.cShortName = csname;
    374     }
    375 
    376     if(options[LIBNAME].doesOccur) { /* get libname from shortname, or explicit -L parameter */
    377       o.libName = options[LIBNAME].value;
    378     } else {
    379       o.libName = o.shortName;
    380     }
    381 
    382     if(options[QUIET].doesOccur) {
    383       o.quiet = TRUE;
    384     } else {
    385       o.quiet = FALSE;
    386     }
    387 
    388     o.verbose   = options[VERBOSE].doesOccur;
    389 
    390 
    391 #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN) /* on UNIX, we'll just include the file... */
    392     if (options[BLDOPT].doesOccur) {
    393         o.options   = options[BLDOPT].value;
    394     } else {
    395         o.options = NULL;
    396     }
    397 #endif
    398     if(options[COPYRIGHT].doesOccur) {
    399         o.comment = U_COPYRIGHT_STRING;
    400     } else if (options[COMMENT].doesOccur) {
    401         o.comment = options[COMMENT].value;
    402     }
    403 
    404     if( options[DESTDIR].doesOccur ) {
    405         o.targetDir = options[DESTDIR].value;
    406     } else {
    407         o.targetDir = ".";  /* cwd */
    408     }
    409 
    410     o.rebuild   = options[REBUILD].doesOccur;
    411 
    412     if( options[TEMPDIR].doesOccur ) {
    413         o.tmpDir    = options[TEMPDIR].value;
    414     } else {
    415         o.tmpDir    = o.targetDir;
    416     }
    417 
    418     if( options[INSTALL].doesOccur ) {
    419         o.install  = options[INSTALL].value;
    420     } else {
    421         o.install = NULL;
    422     }
    423 
    424     if( options[SOURCEDIR].doesOccur ) {
    425         o.srcDir   = options[SOURCEDIR].value;
    426     } else {
    427         o.srcDir   = ".";
    428     }
    429 
    430     if( options[ENTRYPOINT].doesOccur ) {
    431         o.entryName = options[ENTRYPOINT].value;
    432     } else {
    433         o.entryName = o.cShortName;
    434     }
    435 
    436     /* OK options are set up. Now the file lists. */
    437     tail = NULL;
    438     for( n=1; n<argc; n++) {
    439         o.fileListFiles = pkg_appendToList(o.fileListFiles, &tail, uprv_strdup(argv[n]));
    440     }
    441 
    442     /* load the files */
    443     loadLists(&o, &status);
    444     if( U_FAILURE(status) ) {
    445         fprintf(stderr, "error loading input file lists: %s\n", u_errorName(status));
    446         return 2;
    447     }
    448 
    449     result = pkg_executeOptions(&o);
    450 
    451     if (pkgDataFlags != NULL) {
    452         for (n = 0; n < PKGDATA_FLAGS_SIZE; n++) {
    453             if (pkgDataFlags[n] != NULL) {
    454                 uprv_free(pkgDataFlags[n]);
    455             }
    456         }
    457         uprv_free(pkgDataFlags);
    458     }
    459 
    460     if (o.cShortName != NULL) {
    461         uprv_free((char *)o.cShortName);
    462     }
    463     if (o.fileListFiles != NULL) {
    464         pkg_deleteList(o.fileListFiles);
    465     }
    466     if (o.filePaths != NULL) {
    467         pkg_deleteList(o.filePaths);
    468     }
    469     if (o.files != NULL) {
    470         pkg_deleteList(o.files);
    471     }
    472 
    473     return result;
    474 }
    475 
    476 static int runCommand(const char* command, UBool specialHandling) {
    477     char *cmd = NULL;
    478     char cmdBuffer[SMALL_BUFFER_MAX_SIZE];
    479     int32_t len = strlen(command);
    480 
    481     if (len == 0) {
    482         return 0;
    483     }
    484 
    485     if (!specialHandling) {
    486 #if defined(USING_CYGWIN) || defined(OS400)
    487 #define CMD_PADDING_SIZE 20
    488         if ((len + CMD_PADDING_SIZE) >= SMALL_BUFFER_MAX_SIZE) {
    489             cmd = (char *)uprv_malloc(len + CMD_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 #ifdef 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 #ifdef U_CYGWIN
    869             /* Cygwin 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 #ifndef USING_CYGWIN
    890     /* No symbolic link to make. */
    891     if (uprv_strlen(libFileNames[LIB_FILE_VERSION]) == 0 || uprv_strlen(libFileNames[LIB_FILE_VERSION_MAJOR]) == 0 ||
    892         uprv_strcmp(libFileNames[LIB_FILE_VERSION], libFileNames[LIB_FILE_VERSION_MAJOR]) == 0) {
    893         return result;
    894     }
    895 
    896     sprintf(cmd, "cd %s && %s %s && %s %s %s",
    897             targetDir,
    898             RM_CMD,
    899             libFileNames[LIB_FILE_VERSION_MAJOR],
    900             LN_CMD,
    901             libFileNames[LIB_FILE_VERSION],
    902             libFileNames[LIB_FILE_VERSION_MAJOR]);
    903     result = runCommand(cmd);
    904     if (result != 0) {
    905         return result;
    906     }
    907 #endif
    908 
    909     if (specialHandling) {
    910 #ifdef U_CYGWIN
    911         sprintf(name1, "%s", libFileNames[LIB_FILE_CYGWIN]);
    912         sprintf(name2, "%s", libFileNames[LIB_FILE_CYGWIN_VERSION]);
    913 #else
    914         goto normal_symlink_mode;
    915 #endif
    916     } else {
    917 normal_symlink_mode:
    918         sprintf(name1, "%s.%s", libFileNames[LIB_FILE], pkgDataFlags[SO_EXT]);
    919         sprintf(name2, "%s", libFileNames[LIB_FILE_VERSION]);
    920     }
    921 
    922     sprintf(cmd, "cd %s && %s %s && %s %s %s",
    923             targetDir,
    924             RM_CMD,
    925             name1,
    926             LN_CMD,
    927             name2,
    928             name1);
    929 
    930      result = runCommand(cmd);
    931 
    932     return result;
    933 }
    934 
    935 static int32_t pkg_installLibrary(const char *installDir, const char *targetDir) {
    936     int32_t result = 0;
    937     char cmd[SMALL_BUFFER_MAX_SIZE];
    938 
    939     sprintf(cmd, "cd %s && %s %s %s%s%s",
    940             targetDir,
    941             pkgDataFlags[INSTALL_CMD],
    942             libFileNames[LIB_FILE_VERSION],
    943             installDir, PKGDATA_FILE_SEP_STRING, libFileNames[LIB_FILE_VERSION]
    944             );
    945 
    946     result = runCommand(cmd);
    947 
    948     if (result != 0) {
    949         return result;
    950     }
    951 
    952 #ifdef CYGWINMSVC
    953     sprintf(cmd, "cd %s && %s %s.lib %s",
    954             targetDir,
    955             pkgDataFlags[INSTALL_CMD],
    956             libFileNames[LIB_FILE],
    957             installDir
    958             );
    959     result = runCommand(cmd);
    960 
    961     if (result != 0) {
    962         return result;
    963     }
    964 #elif defined (U_CYGWIN)
    965     sprintf(cmd, "cd %s && %s %s %s",
    966             targetDir,
    967             pkgDataFlags[INSTALL_CMD],
    968             libFileNames[LIB_FILE_CYGWIN_VERSION],
    969             installDir
    970             );
    971     result = runCommand(cmd);
    972 
    973     if (result != 0) {
    974         return result;
    975     }
    976 #endif
    977 
    978     return pkg_createSymLinks(installDir, TRUE);
    979 }
    980 
    981 static int32_t pkg_installCommonMode(const char *installDir, const char *fileName) {
    982     int32_t result = 0;
    983     char cmd[SMALL_BUFFER_MAX_SIZE] = "";
    984 
    985     if (!T_FileStream_file_exists(installDir)) {
    986         UErrorCode status = U_ZERO_ERROR;
    987 
    988         uprv_mkdir(installDir, &status);
    989         if (U_FAILURE(status)) {
    990             fprintf(stderr, "Error creating installation directory: %s\n", installDir);
    991             return -1;
    992         }
    993     }
    994 #ifndef U_WINDOWS_WITH_MSVC
    995     sprintf(cmd, "%s %s %s", pkgDataFlags[INSTALL_CMD], fileName, installDir);
    996 #else
    997     sprintf(cmd, "%s %s %s %s", WIN_INSTALL_CMD, fileName, installDir, WIN_INSTALL_CMD_FLAGS);
    998 #endif
    999 
   1000     result = runCommand(cmd);
   1001     if (result != 0) {
   1002         fprintf(stderr, "Failed to install data file with command: %s\n", cmd);
   1003     }
   1004 
   1005     return result;
   1006 }
   1007 
   1008 #ifdef U_WINDOWS_MSVC
   1009 /* Copy commands for installing the raw data files on Windows. */
   1010 #define WIN_INSTALL_CMD "xcopy"
   1011 #define WIN_INSTALL_CMD_FLAGS "/E /Y /K"
   1012 #endif
   1013 static int32_t pkg_installFileMode(const char *installDir, const char *srcDir, const char *fileListName) {
   1014     int32_t result = 0;
   1015     char cmd[SMALL_BUFFER_MAX_SIZE] = "";
   1016 
   1017     if (!T_FileStream_file_exists(installDir)) {
   1018         UErrorCode status = U_ZERO_ERROR;
   1019 
   1020         uprv_mkdir(installDir, &status);
   1021         if (U_FAILURE(status)) {
   1022             fprintf(stderr, "Error creating installation directory: %s\n", installDir);
   1023             return -1;
   1024         }
   1025     }
   1026 #ifndef U_WINDOWS_WITH_MSVC
   1027     char buffer[SMALL_BUFFER_MAX_SIZE] = "";
   1028 
   1029     FileStream *f = T_FileStream_open(fileListName, "r");
   1030     if (f != NULL) {
   1031         for(;;) {
   1032             if (T_FileStream_readLine(f, buffer, SMALL_BUFFER_MAX_SIZE) != NULL) {
   1033                 /* Remove new line character. */
   1034                 buffer[uprv_strlen(buffer)-1] = 0;
   1035 
   1036                 sprintf(cmd, "%s %s%s%s %s%s%s",
   1037                         pkgDataFlags[INSTALL_CMD],
   1038                         srcDir, PKGDATA_FILE_SEP_STRING, buffer,
   1039                         installDir, PKGDATA_FILE_SEP_STRING, buffer);
   1040 
   1041                 result = runCommand(cmd);
   1042                 if (result != 0) {
   1043                     fprintf(stderr, "Failed to install data file with command: %s\n", cmd);
   1044                     break;
   1045                 }
   1046             } else {
   1047                 if (!T_FileStream_eof(f)) {
   1048                     fprintf(stderr, "Failed to read line from file: %s\n", fileListName);
   1049                     result = -1;
   1050                 }
   1051                 break;
   1052             }
   1053         }
   1054         T_FileStream_close(f);
   1055     } else {
   1056         result = -1;
   1057         fprintf(stderr, "Unable to open list file: %s\n", fileListName);
   1058     }
   1059 #else
   1060     sprintf(cmd, "%s %s %s %s", WIN_INSTALL_CMD, srcDir, installDir, WIN_INSTALL_CMD_FLAGS);
   1061     result = runCommand(cmd);
   1062     if (result != 0) {
   1063         fprintf(stderr, "Failed to install data file with command: %s\n", cmd);
   1064     }
   1065 #endif
   1066 
   1067     return result;
   1068 }
   1069 
   1070 /* Archiving of the library file may be needed depending on the platform and options given.
   1071  * If archiving is not needed, copy over the library file name.
   1072  */
   1073 static int32_t pkg_archiveLibrary(const char *targetDir, const char *version, UBool reverseExt) {
   1074     int32_t result = 0;
   1075     char cmd[LARGE_BUFFER_MAX_SIZE];
   1076 
   1077     /* If the shared object suffix and the final object suffix is different and the final object suffix and the
   1078      * archive file suffix is the same, then the final library needs to be archived.
   1079      */
   1080     if (uprv_strcmp(pkgDataFlags[SOBJ_EXT], pkgDataFlags[SO_EXT]) != 0 && uprv_strcmp(pkgDataFlags[A_EXT], pkgDataFlags[SO_EXT]) == 0) {
   1081         sprintf(libFileNames[LIB_FILE_VERSION], "%s%s%s.%s",
   1082                 libFileNames[LIB_FILE],
   1083                 pkgDataFlags[LIB_EXT_ORDER][0] == '.' ? "." : "",
   1084                 reverseExt ? version : pkgDataFlags[SO_EXT],
   1085                 reverseExt ? pkgDataFlags[SO_EXT] : version);
   1086 
   1087         sprintf(cmd, "%s %s %s%s %s%s",
   1088                 pkgDataFlags[AR],
   1089                 pkgDataFlags[ARFLAGS],
   1090                 targetDir,
   1091                 libFileNames[LIB_FILE_VERSION],
   1092                 targetDir,
   1093                 libFileNames[LIB_FILE_VERSION_TMP]);
   1094 
   1095         result = runCommand(cmd);
   1096         if (result != 0) {
   1097             return result;
   1098         }
   1099 
   1100         sprintf(cmd, "%s %s%s",
   1101             pkgDataFlags[RANLIB],
   1102             targetDir,
   1103             libFileNames[LIB_FILE_VERSION]);
   1104 
   1105         result = runCommand(cmd);
   1106         if (result != 0) {
   1107             return result;
   1108         }
   1109 
   1110         /* Remove unneeded library file. */
   1111         sprintf(cmd, "%s %s%s",
   1112                 RM_CMD,
   1113                 targetDir,
   1114                 libFileNames[LIB_FILE_VERSION_TMP]);
   1115 
   1116         result = runCommand(cmd);
   1117         if (result != 0) {
   1118             return result;
   1119         }
   1120 
   1121     } else {
   1122         uprv_strcpy(libFileNames[LIB_FILE_VERSION], libFileNames[LIB_FILE_VERSION_TMP]);
   1123     }
   1124 
   1125     return result;
   1126 }
   1127 
   1128 /*
   1129  * Using the compiler information from the configuration file set by -O option, generate the library file.
   1130  * command may be given to allow for a larger buffer for cmd.
   1131  */
   1132 static int32_t pkg_generateLibraryFile(const char *targetDir, const char mode, const char *objectFile, char *command) {
   1133     int32_t result = 0;
   1134     char *cmd = NULL;
   1135     UBool freeCmd = FALSE;
   1136 
   1137     /* This is necessary because if packaging is done without assembly code, objectFile might be extremely large
   1138      * containing many object files and so the calling function should supply a command buffer that is large
   1139      * enough to handle this. Otherwise, use the default size.
   1140      */
   1141     if (command != NULL) {
   1142         cmd = command;
   1143     } else {
   1144         if ((cmd = (char *)uprv_malloc(sizeof(char) * LARGE_BUFFER_MAX_SIZE)) == NULL) {
   1145             fprintf(stderr, "Unable to allocate memory for command.\n");
   1146             return -1;
   1147         }
   1148         freeCmd = TRUE;
   1149     }
   1150 
   1151     if (mode == MODE_STATIC) {
   1152         sprintf(cmd, "%s %s %s%s %s",
   1153                 pkgDataFlags[AR],
   1154                 pkgDataFlags[ARFLAGS],
   1155                 targetDir,
   1156                 libFileNames[LIB_FILE_VERSION],
   1157                 objectFile);
   1158 
   1159         result = runCommand(cmd);
   1160         if (result == 0) {
   1161             sprintf(cmd, "%s %s%s",
   1162                     pkgDataFlags[RANLIB],
   1163                     targetDir,
   1164                     libFileNames[LIB_FILE_VERSION]);
   1165 
   1166             result = runCommand(cmd);
   1167         }
   1168     } else /* if (mode == MODE_DLL) */ {
   1169 #ifdef U_CYGWIN
   1170         sprintf(cmd, "%s%s%s %s -o %s%s %s %s%s %s %s",
   1171                 pkgDataFlags[GENLIB],
   1172                 targetDir,
   1173                 libFileNames[LIB_FILE_VERSION_TMP],
   1174                 pkgDataFlags[LDICUDTFLAGS],
   1175                 targetDir, libFileNames[LIB_FILE_CYGWIN_VERSION],
   1176 #else
   1177         sprintf(cmd, "%s %s -o %s%s %s %s%s %s %s",
   1178                 pkgDataFlags[GENLIB],
   1179                 pkgDataFlags[LDICUDTFLAGS],
   1180                 targetDir,
   1181                 libFileNames[LIB_FILE_VERSION_TMP],
   1182 #endif
   1183                 objectFile,
   1184                 pkgDataFlags[LD_SONAME],
   1185                 pkgDataFlags[LD_SONAME][0] == 0 ? "" : libFileNames[LIB_FILE_VERSION_MAJOR],
   1186                 pkgDataFlags[RPATH_FLAGS],
   1187                 pkgDataFlags[BIR_FLAGS]);
   1188 
   1189         /* Generate the library file. */
   1190         result = runCommand(cmd);
   1191     }
   1192 
   1193     if (freeCmd) {
   1194         uprv_free(cmd);
   1195     }
   1196 
   1197     return result;
   1198 }
   1199 
   1200 static int32_t pkg_createWithAssemblyCode(const char *targetDir, const char mode, const char *gencFilePath) {
   1201     char tempObjectFile[SMALL_BUFFER_MAX_SIZE] = "";
   1202     char *cmd;
   1203     int32_t result = 0;
   1204 
   1205     int32_t length = 0;
   1206 
   1207     /* Remove the ending .s and replace it with .o for the new object file. */
   1208     uprv_strcpy(tempObjectFile, gencFilePath);
   1209     tempObjectFile[uprv_strlen(tempObjectFile)-1] = 'o';
   1210 
   1211     length = uprv_strlen(pkgDataFlags[COMPILER]) + uprv_strlen(pkgDataFlags[LIBFLAGS])
   1212                     + uprv_strlen(tempObjectFile) + uprv_strlen(gencFilePath) + 10;
   1213 
   1214     cmd = (char *)uprv_malloc(sizeof(char) * length);
   1215     if (cmd == NULL) {
   1216         return -1;
   1217     }
   1218 
   1219     /* Generate the object file. */
   1220     sprintf(cmd, "%s %s -o %s %s",
   1221             pkgDataFlags[COMPILER],
   1222             pkgDataFlags[LIBFLAGS],
   1223             tempObjectFile,
   1224             gencFilePath);
   1225 
   1226     result = runCommand(cmd);
   1227     uprv_free(cmd);
   1228     if (result != 0) {
   1229         return result;
   1230     }
   1231 
   1232     return pkg_generateLibraryFile(targetDir, mode, tempObjectFile);
   1233 }
   1234 
   1235 #ifdef BUILD_DATA_WITHOUT_ASSEMBLY
   1236 /*
   1237  * Generation of the data library without assembly code needs to compile each data file
   1238  * individually and then link it all together.
   1239  * Note: Any update to the directory structure of the data needs to be reflected here.
   1240  */
   1241 enum {
   1242     DATA_PREFIX_BRKITR,
   1243     DATA_PREFIX_COLL,
   1244     DATA_PREFIX_CURR,
   1245     DATA_PREFIX_LANG,
   1246     DATA_PREFIX_RBNF,
   1247     DATA_PREFIX_REGION,
   1248     DATA_PREFIX_TRANSLIT,
   1249     DATA_PREFIX_ZONE,
   1250     DATA_PREFIX_LENGTH
   1251 };
   1252 
   1253 const static char DATA_PREFIX[DATA_PREFIX_LENGTH][10] = {
   1254         "brkitr",
   1255         "coll",
   1256         "curr",
   1257         "lang",
   1258         "rbnf",
   1259         "region",
   1260         "translit",
   1261         "zone"
   1262 };
   1263 
   1264 static int32_t pkg_createWithoutAssemblyCode(UPKGOptions *o, const char *targetDir, const char mode) {
   1265     int32_t result = 0;
   1266     CharList *list = o->filePaths;
   1267     CharList *listNames = o->files;
   1268     int32_t listSize = pkg_countCharList(list);
   1269     char *buffer;
   1270     char *cmd;
   1271     char gencmnFile[SMALL_BUFFER_MAX_SIZE] = "";
   1272     char tempObjectFile[SMALL_BUFFER_MAX_SIZE] = "";
   1273 #ifdef USE_SINGLE_CCODE_FILE
   1274     char icudtAll[SMALL_BUFFER_MAX_SIZE] = "";
   1275 
   1276     sprintf(icudtAll, "%s%s%sall.c",
   1277             o->tmpDir,
   1278             PKGDATA_FILE_SEP_STRING,
   1279             libFileNames[LIB_FILE]);
   1280     /* Remove previous icudtall.c file. */
   1281     if (T_FileStream_file_exists(icudtAll) && (result = remove(icudtAll)) != 0) {
   1282         fprintf(stderr, "Unable to remove old icudtall file: %s\n", icudtAll);
   1283         return result;
   1284     }
   1285 #endif
   1286 
   1287     if (list == NULL || listNames == NULL) {
   1288         /* list and listNames should never be NULL since we are looping through the CharList with
   1289          * the given size.
   1290          */
   1291         return -1;
   1292     }
   1293 
   1294     if ((cmd = (char *)uprv_malloc((listSize + 2) * SMALL_BUFFER_MAX_SIZE)) == NULL) {
   1295         fprintf(stderr, "Unable to allocate memory for cmd.\n");
   1296         return -1;
   1297     } else if ((buffer = (char *)uprv_malloc((listSize + 1) * SMALL_BUFFER_MAX_SIZE)) == NULL) {
   1298         fprintf(stderr, "Unable to allocate memory for buffer.\n");
   1299         uprv_free(cmd);
   1300         return -1;
   1301     }
   1302 
   1303     for (int32_t i = 0; i < (listSize + 1); i++) {
   1304         const char *file ;
   1305         const char *name;
   1306 
   1307         if (i == 0) {
   1308             /* The first iteration calls the gencmn function and initailizes the buffer. */
   1309             createCommonDataFile(o->tmpDir, o->shortName, o->entryName, NULL, o->srcDir, o->comment, o->fileListFiles->str, 0, TRUE, o->verbose, gencmnFile);
   1310             buffer[0] = 0;
   1311 #ifdef USE_SINGLE_CCODE_FILE
   1312             uprv_strcpy(tempObjectFile, gencmnFile);
   1313             tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
   1314 
   1315             sprintf(cmd, "%s %s -o %s %s"
   1316                         pkgDataFlags[COMPILER],
   1317                         pkgDataFlags[LIBFLAGS],
   1318                         tempObjectFile,
   1319                         gencmnFile);
   1320 
   1321             result = runCommand(cmd);
   1322             if (result != 0) {
   1323                 break;
   1324             }
   1325 
   1326             sprintf(buffer, "%s",tempObjectFile);
   1327 #endif
   1328         } else {
   1329             char newName[SMALL_BUFFER_MAX_SIZE];
   1330             char dataName[SMALL_BUFFER_MAX_SIZE];
   1331             char dataDirName[SMALL_BUFFER_MAX_SIZE];
   1332             const char *pSubstring;
   1333             file = list->str;
   1334             name = listNames->str;
   1335 
   1336             newName[0] = dataName[0] = 0;
   1337             for (int32_t n = 0; n < DATA_PREFIX_LENGTH; n++) {
   1338                 dataDirName[0] = 0;
   1339                 sprintf(dataDirName, "%s%s", DATA_PREFIX[n], PKGDATA_FILE_SEP_STRING);
   1340                 /* If the name contains a prefix (indicating directory), alter the new name accordingly. */
   1341                 pSubstring = uprv_strstr(name, dataDirName);
   1342                 if (pSubstring != NULL) {
   1343                     char newNameTmp[SMALL_BUFFER_MAX_SIZE] = "";
   1344                     const char *p = name + uprv_strlen(dataDirName);
   1345                     for (int32_t i = 0;;i++) {
   1346                         if (p[i] == '.') {
   1347                             newNameTmp[i] = '_';
   1348                             continue;
   1349                         }
   1350                         newNameTmp[i] = p[i];
   1351                         if (p[i] == 0) {
   1352                             break;
   1353                         }
   1354                     }
   1355                     sprintf(newName, "%s_%s",
   1356                             DATA_PREFIX[n],
   1357                             newNameTmp);
   1358                     sprintf(dataName, "%s_%s",
   1359                             o->shortName,
   1360                             DATA_PREFIX[n]);
   1361                 }
   1362                 if (newName[0] != 0) {
   1363                     break;
   1364                 }
   1365             }
   1366 
   1367             writeCCode(file, o->tmpDir, dataName[0] != 0 ? dataName : o->shortName, newName[0] != 0 ? newName : NULL, gencmnFile);
   1368 #ifdef USE_SINGLE_CCODE_FILE
   1369             sprintf(cmd, "cat %s >> %s", gencmnFile, icudtAll);
   1370 
   1371             result = runCommand(cmd);
   1372             if (result != 0) {
   1373                 break;
   1374             } else {
   1375                 /* Remove the c code file after concatenating it to icudtall.c file. */
   1376                 if ((result = remove(gencmnFile)) != 0) {
   1377                     fprintf(stderr, "Unable to remove c code file: %s\n", gencmnFile);
   1378                     return result;
   1379                 }
   1380             }
   1381 #endif
   1382         }
   1383 
   1384 #ifndef USE_SINGLE_CCODE_FILE
   1385         uprv_strcpy(tempObjectFile, gencmnFile);
   1386         tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
   1387 
   1388         sprintf(cmd, "%s %s -o %s %s",
   1389                     pkgDataFlags[COMPILER],
   1390                     pkgDataFlags[LIBFLAGS],
   1391                     tempObjectFile,
   1392                     gencmnFile);
   1393         result = runCommand(cmd);
   1394         if (result != 0) {
   1395             break;
   1396         }
   1397 
   1398         uprv_strcat(buffer, " ");
   1399         uprv_strcat(buffer, tempObjectFile);
   1400 
   1401 #endif
   1402 
   1403         if (i > 0) {
   1404             list = list->next;
   1405             listNames = listNames->next;
   1406         }
   1407     }
   1408 
   1409 #ifdef USE_SINGLE_CCODE_FILE
   1410     uprv_strcpy(tempObjectFile, icudtAll);
   1411     tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
   1412 
   1413     sprintf(cmd, "%s %s -o %s %s",
   1414         pkgDataFlags[COMPILER],
   1415         pkgDataFlags[LIBFLAGS],
   1416         tempObjectFile,
   1417         icudtAll);
   1418 
   1419     result = runCommand(cmd);
   1420     if (result == 0) {
   1421         uprv_strcat(buffer, " ");
   1422         uprv_strcat(buffer, tempObjectFile);
   1423     }
   1424 #endif
   1425 
   1426     if (result == 0) {
   1427         /* Generate the library file. */
   1428         result = pkg_generateLibraryFile(targetDir, mode, buffer, cmd);
   1429     }
   1430 
   1431     uprv_free(buffer);
   1432     uprv_free(cmd);
   1433 
   1434     return result;
   1435 }
   1436 #endif
   1437 
   1438 #ifdef WINDOWS_WITH_MSVC
   1439 #define LINK_CMD "link.exe /nologo /release /out:"
   1440 #define LINK_FLAGS "/DLL /NOENTRY /MANIFEST:NO  /base:0x4ad00000 /implib:"
   1441 #define LIB_CMD "LIB.exe /nologo /out:"
   1442 #define LIB_FILE "icudt.lib"
   1443 #define LIB_EXT UDATA_LIB_SUFFIX
   1444 #define DLL_EXT UDATA_SO_SUFFIX
   1445 
   1446 static int32_t pkg_createWindowsDLL(const char mode, const char *gencFilePath, UPKGOptions *o) {
   1447     char cmd[LARGE_BUFFER_MAX_SIZE];
   1448     if (mode == MODE_STATIC) {
   1449         char staticLibFilePath[SMALL_BUFFER_MAX_SIZE] = "";
   1450 
   1451         uprv_strcpy(staticLibFilePath, o->tmpDir);
   1452         uprv_strcat(staticLibFilePath, PKGDATA_FILE_SEP_STRING);
   1453 
   1454         uprv_strcat(staticLibFilePath, o->entryName);
   1455         uprv_strcat(staticLibFilePath, LIB_EXT);
   1456 
   1457         sprintf(cmd, "%s\"%s\" \"%s\"",
   1458                 LIB_CMD,
   1459                 staticLibFilePath,
   1460                 gencFilePath);
   1461     } else if (mode == MODE_DLL) {
   1462         char dllFilePath[SMALL_BUFFER_MAX_SIZE] = "";
   1463         char libFilePath[SMALL_BUFFER_MAX_SIZE] = "";
   1464         char resFilePath[SMALL_BUFFER_MAX_SIZE] = "";
   1465         char tmpResFilePath[SMALL_BUFFER_MAX_SIZE] = "";
   1466 
   1467 #ifdef CYGWINMSVC
   1468         uprv_strcpy(dllFilePath, o->targetDir);
   1469 #else
   1470         uprv_strcpy(dllFilePath, o->srcDir);
   1471 #endif
   1472         uprv_strcat(dllFilePath, PKGDATA_FILE_SEP_STRING);
   1473         uprv_strcpy(libFilePath, dllFilePath);
   1474 
   1475 #ifdef CYGWINMSVC
   1476         uprv_strcat(libFilePath, o->libName);
   1477         uprv_strcat(libFilePath, ".lib");
   1478 
   1479         uprv_strcat(dllFilePath, o->libName);
   1480         uprv_strcat(dllFilePath, o->version);
   1481 #else
   1482         if (strstr(o->libName, "icudt")) {
   1483             uprv_strcat(libFilePath, LIB_FILE);
   1484         } else {
   1485             uprv_strcat(libFilePath, o->libName);
   1486             uprv_strcat(libFilePath, ".lib");
   1487         }
   1488         uprv_strcat(dllFilePath, o->entryName);
   1489 #endif
   1490         uprv_strcat(dllFilePath, DLL_EXT);
   1491 
   1492         uprv_strcpy(tmpResFilePath, o->tmpDir);
   1493         uprv_strcat(tmpResFilePath, PKGDATA_FILE_SEP_STRING);
   1494         uprv_strcat(tmpResFilePath, ICUDATA_RES_FILE);
   1495 
   1496         if (T_FileStream_file_exists(tmpResFilePath)) {
   1497             sprintf(resFilePath, "\"%s\"", tmpResFilePath);
   1498         }
   1499 
   1500         /* Check if dll file and lib file exists and that it is not newer than genc file. */
   1501         if (!o->rebuild && (T_FileStream_file_exists(dllFilePath) && isFileModTimeLater(dllFilePath, gencFilePath)) &&
   1502             (T_FileStream_file_exists(libFilePath) && isFileModTimeLater(libFilePath, gencFilePath))) {
   1503           if(o->verbose) {
   1504             printf("# Not rebuilding %s - up to date.\n", gencFilePath);
   1505           }
   1506           return 0;
   1507         }
   1508 
   1509         sprintf(cmd, "%s\"%s\" %s\"%s\" \"%s\" %s",
   1510                 LINK_CMD,
   1511                 dllFilePath,
   1512                 LINK_FLAGS,
   1513                 libFilePath,
   1514                 gencFilePath,
   1515                 resFilePath
   1516                 );
   1517     }
   1518 
   1519     return runCommand(cmd, TRUE);
   1520 }
   1521 #endif
   1522 
   1523 static UPKGOptions *pkg_checkFlag(UPKGOptions *o) {
   1524 #ifdef U_AIX
   1525     /* AIX needs a map file. */
   1526     char *flag = NULL;
   1527     int32_t length = 0;
   1528     char tmpbuffer[SMALL_BUFFER_MAX_SIZE];
   1529     const char MAP_FILE_EXT[] = ".map";
   1530     FileStream *f = NULL;
   1531     char mapFile[SMALL_BUFFER_MAX_SIZE] = "";
   1532     int32_t start = -1;
   1533     int32_t count = 0;
   1534 
   1535     flag = pkgDataFlags[BIR_FLAGS];
   1536     length = uprv_strlen(pkgDataFlags[BIR_FLAGS]);
   1537 
   1538     for (int32_t i = 0; i < length; i++) {
   1539         if (flag[i] == MAP_FILE_EXT[count]) {
   1540             if (count == 0) {
   1541                 start = i;
   1542             }
   1543             count++;
   1544         } else {
   1545             count = 0;
   1546         }
   1547 
   1548         if (count == uprv_strlen(MAP_FILE_EXT)) {
   1549             break;
   1550         }
   1551     }
   1552 
   1553     if (start >= 0) {
   1554         int32_t index = 0;
   1555         for (int32_t i = 0;;i++) {
   1556             if (i == start) {
   1557                 for (int32_t n = 0;;n++) {
   1558                     if (o->shortName[n] == 0) {
   1559                         break;
   1560                     }
   1561                     tmpbuffer[index++] = o->shortName[n];
   1562                 }
   1563             }
   1564 
   1565             tmpbuffer[index++] = flag[i];
   1566 
   1567             if (flag[i] == 0) {
   1568                 break;
   1569             }
   1570         }
   1571 
   1572         uprv_memset(flag, 0, length);
   1573         uprv_strcpy(flag, tmpbuffer);
   1574 
   1575         uprv_strcpy(mapFile, o->shortName);
   1576         uprv_strcat(mapFile, MAP_FILE_EXT);
   1577 
   1578         f = T_FileStream_open(mapFile, "w");
   1579         if (f == NULL) {
   1580             fprintf(stderr,"Unable to create map file: %s.\n", mapFile);
   1581         } else {
   1582             sprintf(tmpbuffer, "%s%s ", o->entryName, UDATA_CMN_INTERMEDIATE_SUFFIX);
   1583 
   1584             T_FileStream_writeLine(f, tmpbuffer);
   1585 
   1586             T_FileStream_close(f);
   1587         }
   1588     }
   1589 #elif defined(U_CYGWIN)
   1590     /* Cygwin needs to change flag options. */
   1591     char *flag = NULL;
   1592     int32_t length = 0;
   1593 
   1594     flag = pkgDataFlags[GENLIB];
   1595     length = uprv_strlen(pkgDataFlags[GENLIB]);
   1596 
   1597     int32_t position = length - 1;
   1598 
   1599     for(;position >= 0;position--) {
   1600         if (flag[position] == '=') {
   1601             position++;
   1602             break;
   1603         }
   1604     }
   1605 
   1606     uprv_memset(flag + position, 0, length - position);
   1607 #elif defined(OS400)
   1608     /* OS400 needs to fix the ld options (swap single quote with double quote) */
   1609     char *flag = NULL;
   1610     int32_t length = 0;
   1611 
   1612     flag = pkgDataFlags[GENLIB];
   1613     length = uprv_strlen(pkgDataFlags[GENLIB]);
   1614 
   1615     int32_t position = length - 1;
   1616 
   1617     for(int32_t i = 0; i < length; i++) {
   1618         if (flag[i] == '\'') {
   1619             flag[i] = '\"';
   1620         }
   1621     }
   1622 #endif
   1623     // Don't really need a return value, just need to stop compiler warnings about
   1624     // the unused parameter 'o' on platforms where it is not otherwise used.
   1625     return o;
   1626 }
   1627 
   1628 static void loadLists(UPKGOptions *o, UErrorCode *status)
   1629 {
   1630     CharList   *l, *tail = NULL, *tail2 = NULL;
   1631     FileStream *in;
   1632     char        line[16384];
   1633     char       *linePtr, *lineNext;
   1634     const uint32_t   lineMax = 16300;
   1635     char        tmp[1024];
   1636     char       *s;
   1637     int32_t     ln=0; /* line number */
   1638 
   1639     for(l = o->fileListFiles; l; l = l->next) {
   1640         if(o->verbose) {
   1641             fprintf(stdout, "# pkgdata: Reading %s..\n", l->str);
   1642         }
   1643         /* TODO: stdin */
   1644         in = T_FileStream_open(l->str, "r"); /* open files list */
   1645 
   1646         if(!in) {
   1647             fprintf(stderr, "Error opening <%s>.\n", l->str);
   1648             *status = U_FILE_ACCESS_ERROR;
   1649             return;
   1650         }
   1651 
   1652         while(T_FileStream_readLine(in, line, sizeof(line))!=NULL) { /* for each line */
   1653             ln++;
   1654             if(uprv_strlen(line)>lineMax) {
   1655                 fprintf(stderr, "%s:%d - line too long (over %d chars)\n", l->str, (int)ln, (int)lineMax);
   1656                 exit(1);
   1657             }
   1658             /* remove spaces at the beginning */
   1659             linePtr = line;
   1660             while(isspace(*linePtr)) {
   1661                 linePtr++;
   1662             }
   1663             s=linePtr;
   1664             /* remove trailing newline characters */
   1665             while(*s!=0) {
   1666                 if(*s=='\r' || *s=='\n') {
   1667                     *s=0;
   1668                     break;
   1669                 }
   1670                 ++s;
   1671             }
   1672             if((*linePtr == 0) || (*linePtr == '#')) {
   1673                 continue; /* comment or empty line */
   1674             }
   1675 
   1676             /* Now, process the line */
   1677             lineNext = NULL;
   1678 
   1679             while(linePtr && *linePtr) { /* process space-separated items */
   1680                 while(*linePtr == ' ') {
   1681                     linePtr++;
   1682                 }
   1683                 /* Find the next quote */
   1684                 if(linePtr[0] == '"')
   1685                 {
   1686                     lineNext = uprv_strchr(linePtr+1, '"');
   1687                     if(lineNext == NULL) {
   1688                         fprintf(stderr, "%s:%d - missing trailing double quote (\")\n",
   1689                             l->str, (int)ln);
   1690                         exit(1);
   1691                     } else {
   1692                         lineNext++;
   1693                         if(*lineNext) {
   1694                             if(*lineNext != ' ') {
   1695                                 fprintf(stderr, "%s:%d - malformed quoted line at position %d, expected ' ' got '%c'\n",
   1696                                     l->str, (int)ln, (int)(lineNext-line), (*lineNext)?*lineNext:'0');
   1697                                 exit(1);
   1698                             }
   1699                             *lineNext = 0;
   1700                             lineNext++;
   1701                         }
   1702                     }
   1703                 } else {
   1704                     lineNext = uprv_strchr(linePtr, ' ');
   1705                     if(lineNext) {
   1706                         *lineNext = 0; /* terminate at space */
   1707                         lineNext++;
   1708                     }
   1709                 }
   1710 
   1711                 /* add the file */
   1712                 s = (char*)getLongPathname(linePtr);
   1713 
   1714                 /* normal mode.. o->files is just the bare list without package names */
   1715                 o->files = pkg_appendToList(o->files, &tail, uprv_strdup(linePtr));
   1716                 if(uprv_pathIsAbsolute(s)) {
   1717                     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);
   1718                     exit(U_ILLEGAL_ARGUMENT_ERROR);
   1719                 }
   1720                 uprv_strcpy(tmp, o->srcDir);
   1721                 uprv_strcat(tmp, o->srcDir[uprv_strlen(o->srcDir)-1] == U_FILE_SEP_CHAR ? "" :PKGDATA_FILE_SEP_STRING);
   1722                 uprv_strcat(tmp, s);
   1723                 o->filePaths = pkg_appendToList(o->filePaths, &tail2, uprv_strdup(tmp));
   1724                 linePtr = lineNext;
   1725             } /* for each entry on line */
   1726         } /* for each line */
   1727         T_FileStream_close(in);
   1728     } /* for each file list file */
   1729 }
   1730 
   1731 /* Try calling icu-config directly to get the option file. */
   1732  static int32_t pkg_getOptionsFromICUConfig(UBool verbose, UOption *option) {
   1733 #if U_HAVE_POPEN
   1734     FILE *p = NULL;
   1735     size_t n;
   1736     static char buf[512] = "";
   1737     char cmdBuf[1024];
   1738     UErrorCode status = U_ZERO_ERROR;
   1739     const char cmd[] = "icu-config --incpkgdatafile";
   1740 
   1741     /* #1 try the same path where pkgdata was called from. */
   1742     findDirname(progname, cmdBuf, 1024, &status);
   1743     if(U_SUCCESS(status)) {
   1744       uprv_strncat(cmdBuf, U_FILE_SEP_STRING, 1024);
   1745       uprv_strncat(cmdBuf, cmd, 1024);
   1746 
   1747       if(verbose) {
   1748         fprintf(stdout, "# Calling icu-config: %s\n", cmdBuf);
   1749       }
   1750       p = popen(cmdBuf, "r");
   1751     }
   1752 
   1753     if(p == NULL) {
   1754       if(verbose) {
   1755         fprintf(stdout, "# Calling icu-config: %s\n", cmd);
   1756       }
   1757       p = popen(cmd, "r");
   1758     }
   1759 
   1760     if(p == NULL)
   1761     {
   1762         fprintf(stderr, "%s: icu-config: No icu-config found. (fix PATH or use -O option)\n", progname);
   1763         return -1;
   1764     }
   1765 
   1766     n = fread(buf, 1, 511, p);
   1767 
   1768     pclose(p);
   1769 
   1770     if(n<=0)
   1771     {
   1772         fprintf(stderr,"%s: icu-config: Could not read from icu-config. (fix PATH or use -O option)\n", progname);
   1773         return -1;
   1774     }
   1775 
   1776     for (int32_t length = strlen(buf) - 1; length >= 0; length--) {
   1777         if (buf[length] == '\n' || buf[length] == ' ') {
   1778             buf[length] = 0;
   1779         } else {
   1780             break;
   1781         }
   1782     }
   1783 
   1784     if(buf[strlen(buf)-1]=='\n')
   1785     {
   1786         buf[strlen(buf)-1]=0;
   1787     }
   1788 
   1789     if(buf[0] == 0)
   1790     {
   1791         fprintf(stderr, "%s: icu-config: invalid response from icu-config (fix PATH or use -O option)\n", progname);
   1792         return -1;
   1793     }
   1794 
   1795     if(verbose) {
   1796       fprintf(stdout, "# icu-config said: %s\n", buf);
   1797     }
   1798 
   1799     option->value = buf;
   1800     option->doesOccur = TRUE;
   1801 
   1802     return 0;
   1803 #endif
   1804     return -1;
   1805 }
   1806