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