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#if U_PLATFORM == U_PF_OS390 && defined(OS390BATCH)
1331        char PDS_LibName[512];
1332        if (uprv_strcmp(libFileNames[LIB_FILE],"libicudata") == 0) {
1333            sprintf(PDS_LibName,"%s%s%s",
1334                    "\"//'",
1335                    getenv("LOADMOD"),
1336                    "(IXMI" U_ICU_VERSION_SHORT "DA)'\"");
1337        } else if (uprv_strcmp(libFileNames[LIB_FILE],"libicudata_stub") == 0) {
1338           sprintf(PDS_LibName,"%s%s%s",
1339                   "\"//'",
1340                   getenv("LOADMOD"),
1341                   "(IXMI" U_ICU_VERSION_SHORT "D1)'\"");
1342           sprintf(cmd, "%s %s -o %s %s %s%s %s %s",
1343                   pkgDataFlags[GENLIB],
1344                   pkgDataFlags[LDICUDTFLAGS],
1345                   PDS_LibName,
1346                   objectFile,
1347                   pkgDataFlags[LD_SONAME],
1348                   pkgDataFlags[LD_SONAME][0] == 0 ? "" : libFileNames[LIB_FILE_VERSION_MAJOR],
1349                   pkgDataFlags[RPATH_FLAGS],
1350                   pkgDataFlags[BIR_FLAGS]);
1351        }
1352        result = runCommand(cmd);
1353#endif
1354    }
1355
1356    if (result != 0) {
1357        fprintf(stderr, "Error generating library file. Failed command: %s\n", cmd);
1358    }
1359
1360    if (freeCmd) {
1361        uprv_free(cmd);
1362    }
1363
1364    return result;
1365}
1366
1367static int32_t pkg_createWithAssemblyCode(const char *targetDir, const char mode, const char *gencFilePath) {
1368    char tempObjectFile[SMALL_BUFFER_MAX_SIZE] = "";
1369    char *cmd;
1370    int32_t result = 0;
1371
1372    int32_t length = 0;
1373
1374    /* Remove the ending .s and replace it with .o for the new object file. */
1375    uprv_strcpy(tempObjectFile, gencFilePath);
1376    tempObjectFile[uprv_strlen(tempObjectFile)-1] = 'o';
1377
1378    length = uprv_strlen(pkgDataFlags[COMPILER]) + uprv_strlen(pkgDataFlags[LIBFLAGS])
1379                    + uprv_strlen(tempObjectFile) + uprv_strlen(gencFilePath) + BUFFER_PADDING_SIZE;
1380
1381    cmd = (char *)uprv_malloc(sizeof(char) * length);
1382    if (cmd == NULL) {
1383        return -1;
1384    }
1385
1386    /* Generate the object file. */
1387    sprintf(cmd, "%s %s -o %s %s",
1388            pkgDataFlags[COMPILER],
1389            pkgDataFlags[LIBFLAGS],
1390            tempObjectFile,
1391            gencFilePath);
1392
1393    result = runCommand(cmd);
1394    uprv_free(cmd);
1395    if (result != 0) {
1396        fprintf(stderr, "Error creating with assembly code. Failed command: %s\n", cmd);
1397        return result;
1398    }
1399
1400    return pkg_generateLibraryFile(targetDir, mode, tempObjectFile);
1401}
1402
1403#ifdef BUILD_DATA_WITHOUT_ASSEMBLY
1404/*
1405 * Generation of the data library without assembly code needs to compile each data file
1406 * individually and then link it all together.
1407 * Note: Any update to the directory structure of the data needs to be reflected here.
1408 */
1409enum {
1410    DATA_PREFIX_BRKITR,
1411    DATA_PREFIX_COLL,
1412    DATA_PREFIX_CURR,
1413    DATA_PREFIX_LANG,
1414    DATA_PREFIX_RBNF,
1415    DATA_PREFIX_REGION,
1416    DATA_PREFIX_TRANSLIT,
1417    DATA_PREFIX_ZONE,
1418    DATA_PREFIX_LENGTH
1419};
1420
1421const static char DATA_PREFIX[DATA_PREFIX_LENGTH][10] = {
1422        "brkitr",
1423        "coll",
1424        "curr",
1425        "lang",
1426        "rbnf",
1427        "region",
1428        "translit",
1429        "zone"
1430};
1431
1432static int32_t pkg_createWithoutAssemblyCode(UPKGOptions *o, const char *targetDir, const char mode) {
1433    int32_t result = 0;
1434    CharList *list = o->filePaths;
1435    CharList *listNames = o->files;
1436    int32_t listSize = pkg_countCharList(list);
1437    char *buffer;
1438    char *cmd;
1439    char gencmnFile[SMALL_BUFFER_MAX_SIZE] = "";
1440    char tempObjectFile[SMALL_BUFFER_MAX_SIZE] = "";
1441#ifdef USE_SINGLE_CCODE_FILE
1442    char icudtAll[SMALL_BUFFER_MAX_SIZE] = "";
1443    FileStream *icudtAllFile = NULL;
1444
1445    sprintf(icudtAll, "%s%s%sall.c",
1446            o->tmpDir,
1447            PKGDATA_FILE_SEP_STRING,
1448            libFileNames[LIB_FILE]);
1449    /* Remove previous icudtall.c file. */
1450    if (T_FileStream_file_exists(icudtAll) && (result = remove(icudtAll)) != 0) {
1451        fprintf(stderr, "Unable to remove old icudtall file: %s\n", icudtAll);
1452        return result;
1453    }
1454
1455    if((icudtAllFile = T_FileStream_open(icudtAll, "w"))==NULL) {
1456        fprintf(stderr, "Unable to write to icudtall file: %s\n", icudtAll);
1457        return result;
1458    }
1459#endif
1460
1461    if (list == NULL || listNames == NULL) {
1462        /* list and listNames should never be NULL since we are looping through the CharList with
1463         * the given size.
1464         */
1465        return -1;
1466    }
1467
1468    if ((cmd = (char *)uprv_malloc((listSize + 2) * SMALL_BUFFER_MAX_SIZE)) == NULL) {
1469        fprintf(stderr, "Unable to allocate memory for cmd.\n");
1470        return -1;
1471    } else if ((buffer = (char *)uprv_malloc((listSize + 1) * SMALL_BUFFER_MAX_SIZE)) == NULL) {
1472        fprintf(stderr, "Unable to allocate memory for buffer.\n");
1473        uprv_free(cmd);
1474        return -1;
1475    }
1476
1477    for (int32_t i = 0; i < (listSize + 1); i++) {
1478        const char *file ;
1479        const char *name;
1480
1481        if (i == 0) {
1482            /* The first iteration calls the gencmn function and initailizes the buffer. */
1483            createCommonDataFile(o->tmpDir, o->shortName, o->entryName, NULL, o->srcDir, o->comment, o->fileListFiles->str, 0, TRUE, o->verbose, gencmnFile);
1484            buffer[0] = 0;
1485#ifdef USE_SINGLE_CCODE_FILE
1486            uprv_strcpy(tempObjectFile, gencmnFile);
1487            tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
1488
1489            sprintf(cmd, "%s %s -o %s %s",
1490                        pkgDataFlags[COMPILER],
1491                        pkgDataFlags[LIBFLAGS],
1492                        tempObjectFile,
1493                        gencmnFile);
1494
1495            result = runCommand(cmd);
1496            if (result != 0) {
1497                break;
1498            }
1499
1500            sprintf(buffer, "%s",tempObjectFile);
1501#endif
1502        } else {
1503            char newName[SMALL_BUFFER_MAX_SIZE];
1504            char dataName[SMALL_BUFFER_MAX_SIZE];
1505            char dataDirName[SMALL_BUFFER_MAX_SIZE];
1506            const char *pSubstring;
1507            file = list->str;
1508            name = listNames->str;
1509
1510            newName[0] = dataName[0] = 0;
1511            for (int32_t n = 0; n < DATA_PREFIX_LENGTH; n++) {
1512                dataDirName[0] = 0;
1513                sprintf(dataDirName, "%s%s", DATA_PREFIX[n], PKGDATA_FILE_SEP_STRING);
1514                /* If the name contains a prefix (indicating directory), alter the new name accordingly. */
1515                pSubstring = uprv_strstr(name, dataDirName);
1516                if (pSubstring != NULL) {
1517                    char newNameTmp[SMALL_BUFFER_MAX_SIZE] = "";
1518                    const char *p = name + uprv_strlen(dataDirName);
1519                    for (int32_t i = 0;;i++) {
1520                        if (p[i] == '.') {
1521                            newNameTmp[i] = '_';
1522                            continue;
1523                        }
1524                        newNameTmp[i] = p[i];
1525                        if (p[i] == 0) {
1526                            break;
1527                        }
1528                    }
1529                    sprintf(newName, "%s_%s",
1530                            DATA_PREFIX[n],
1531                            newNameTmp);
1532                    sprintf(dataName, "%s_%s",
1533                            o->shortName,
1534                            DATA_PREFIX[n]);
1535                }
1536                if (newName[0] != 0) {
1537                    break;
1538                }
1539            }
1540
1541            if(o->verbose) {
1542              printf("# Generating %s \n", gencmnFile);
1543            }
1544
1545            writeCCode(file, o->tmpDir, dataName[0] != 0 ? dataName : o->shortName, newName[0] != 0 ? newName : NULL, gencmnFile);
1546
1547#ifdef USE_SINGLE_CCODE_FILE
1548            sprintf(cmd, "#include \"%s\"\n", gencmnFile);
1549            T_FileStream_writeLine(icudtAllFile, cmd);
1550            /* don't delete the file */
1551#endif
1552        }
1553
1554#ifndef USE_SINGLE_CCODE_FILE
1555        uprv_strcpy(tempObjectFile, gencmnFile);
1556        tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
1557
1558        sprintf(cmd, "%s %s -o %s %s",
1559                    pkgDataFlags[COMPILER],
1560                    pkgDataFlags[LIBFLAGS],
1561                    tempObjectFile,
1562                    gencmnFile);
1563        result = runCommand(cmd);
1564        if (result != 0) {
1565            fprintf(stderr, "Error creating library without assembly code. Failed command: %s\n", cmd);
1566            break;
1567        }
1568
1569        uprv_strcat(buffer, " ");
1570        uprv_strcat(buffer, tempObjectFile);
1571
1572#endif
1573
1574        if (i > 0) {
1575            list = list->next;
1576            listNames = listNames->next;
1577        }
1578    }
1579
1580#ifdef USE_SINGLE_CCODE_FILE
1581    T_FileStream_close(icudtAllFile);
1582    uprv_strcpy(tempObjectFile, icudtAll);
1583    tempObjectFile[uprv_strlen(tempObjectFile) - 1] = 'o';
1584
1585    sprintf(cmd, "%s %s -I. -o %s %s",
1586        pkgDataFlags[COMPILER],
1587        pkgDataFlags[LIBFLAGS],
1588        tempObjectFile,
1589        icudtAll);
1590
1591    result = runCommand(cmd);
1592    if (result == 0) {
1593        uprv_strcat(buffer, " ");
1594        uprv_strcat(buffer, tempObjectFile);
1595    } else {
1596        fprintf(stderr, "Error creating library without assembly code. Failed command: %s\n", cmd);
1597    }
1598#endif
1599
1600    if (result == 0) {
1601        /* Generate the library file. */
1602#if U_PLATFORM == U_PF_OS390
1603        if (o->pdsbuild && IN_DLL_MODE(mode)) {
1604            result = pkg_generateLibraryFile("",mode, buffer, cmd);
1605        } else {
1606            result = pkg_generateLibraryFile(targetDir,mode, buffer, cmd);
1607        }
1608#else
1609        result = pkg_generateLibraryFile(targetDir,mode, buffer, cmd);
1610#endif
1611    }
1612
1613    uprv_free(buffer);
1614    uprv_free(cmd);
1615
1616    return result;
1617}
1618#endif
1619
1620#ifdef WINDOWS_WITH_MSVC
1621#define LINK_CMD "link.exe /nologo /release /out:"
1622#define LINK_FLAGS "/DLL /NOENTRY /MANIFEST:NO  /base:0x4ad00000 /implib:"
1623#define LIB_CMD "LIB.exe /nologo /out:"
1624#define LIB_FILE "icudt.lib"
1625#define LIB_EXT UDATA_LIB_SUFFIX
1626#define DLL_EXT UDATA_SO_SUFFIX
1627
1628static int32_t pkg_createWindowsDLL(const char mode, const char *gencFilePath, UPKGOptions *o) {
1629    int32_t result = 0;
1630    char cmd[LARGE_BUFFER_MAX_SIZE];
1631    if (IN_STATIC_MODE(mode)) {
1632        char staticLibFilePath[SMALL_BUFFER_MAX_SIZE] = "";
1633
1634#ifdef CYGWINMSVC
1635        sprintf(staticLibFilePath, "%s%s%s%s%s",
1636                o->targetDir,
1637                PKGDATA_FILE_SEP_STRING,
1638                pkgDataFlags[LIBPREFIX],
1639                o->libName,
1640                LIB_EXT);
1641#else
1642        sprintf(staticLibFilePath, "%s%s%s%s%s",
1643                o->targetDir,
1644                PKGDATA_FILE_SEP_STRING,
1645                (strstr(o->libName, "icudt") ? "s" : ""),
1646                o->libName,
1647                LIB_EXT);
1648#endif
1649
1650        sprintf(cmd, "%s\"%s\" \"%s\"",
1651                LIB_CMD,
1652                staticLibFilePath,
1653                gencFilePath);
1654    } else if (IN_DLL_MODE(mode)) {
1655        char dllFilePath[SMALL_BUFFER_MAX_SIZE] = "";
1656        char libFilePath[SMALL_BUFFER_MAX_SIZE] = "";
1657        char resFilePath[SMALL_BUFFER_MAX_SIZE] = "";
1658        char tmpResFilePath[SMALL_BUFFER_MAX_SIZE] = "";
1659
1660#ifdef CYGWINMSVC
1661        uprv_strcpy(dllFilePath, o->targetDir);
1662#else
1663        uprv_strcpy(dllFilePath, o->srcDir);
1664#endif
1665        uprv_strcat(dllFilePath, PKGDATA_FILE_SEP_STRING);
1666        uprv_strcpy(libFilePath, dllFilePath);
1667
1668#ifdef CYGWINMSVC
1669        uprv_strcat(libFilePath, o->libName);
1670        uprv_strcat(libFilePath, ".lib");
1671
1672        uprv_strcat(dllFilePath, o->libName);
1673        uprv_strcat(dllFilePath, o->version);
1674#else
1675        if (strstr(o->libName, "icudt")) {
1676            uprv_strcat(libFilePath, LIB_FILE);
1677        } else {
1678            uprv_strcat(libFilePath, o->libName);
1679            uprv_strcat(libFilePath, ".lib");
1680        }
1681        uprv_strcat(dllFilePath, o->entryName);
1682#endif
1683        uprv_strcat(dllFilePath, DLL_EXT);
1684
1685        uprv_strcpy(tmpResFilePath, o->tmpDir);
1686        uprv_strcat(tmpResFilePath, PKGDATA_FILE_SEP_STRING);
1687        uprv_strcat(tmpResFilePath, ICUDATA_RES_FILE);
1688
1689        if (T_FileStream_file_exists(tmpResFilePath)) {
1690            sprintf(resFilePath, "\"%s\"", tmpResFilePath);
1691        }
1692
1693        /* Check if dll file and lib file exists and that it is not newer than genc file. */
1694        if (!o->rebuild && (T_FileStream_file_exists(dllFilePath) && isFileModTimeLater(dllFilePath, gencFilePath)) &&
1695            (T_FileStream_file_exists(libFilePath) && isFileModTimeLater(libFilePath, gencFilePath))) {
1696          if(o->verbose) {
1697            printf("# Not rebuilding %s - up to date.\n", gencFilePath);
1698          }
1699          return 0;
1700        }
1701
1702        sprintf(cmd, "%s\"%s\" %s\"%s\" \"%s\" %s",
1703                LINK_CMD,
1704                dllFilePath,
1705                LINK_FLAGS,
1706                libFilePath,
1707                gencFilePath,
1708                resFilePath
1709                );
1710    }
1711
1712    result = runCommand(cmd, TRUE);
1713    if (result != 0) {
1714        fprintf(stderr, "Error creating Windows DLL library. Failed command: %s\n", cmd);
1715    }
1716
1717    return result;
1718}
1719#endif
1720
1721static UPKGOptions *pkg_checkFlag(UPKGOptions *o) {
1722#if U_PLATFORM == U_PF_AIX
1723    /* AIX needs a map file. */
1724    char *flag = NULL;
1725    int32_t length = 0;
1726    char tmpbuffer[SMALL_BUFFER_MAX_SIZE];
1727    const char MAP_FILE_EXT[] = ".map";
1728    FileStream *f = NULL;
1729    char mapFile[SMALL_BUFFER_MAX_SIZE] = "";
1730    int32_t start = -1;
1731    uint32_t count = 0;
1732    const char rm_cmd[] = "rm -f all ;";
1733
1734    flag = pkgDataFlags[GENLIB];
1735
1736    /* This portion of the code removes 'rm -f all' in the GENLIB.
1737     * Only occurs in AIX.
1738     */
1739    if (uprv_strstr(flag, rm_cmd) != NULL) {
1740        char *tmpGenlibFlagBuffer = NULL;
1741        int32_t i, offset;
1742
1743        length = uprv_strlen(flag) + 1;
1744        tmpGenlibFlagBuffer = (char *)uprv_malloc(length);
1745        if (tmpGenlibFlagBuffer == NULL) {
1746            /* Memory allocation error */
1747            fprintf(stderr,"Unable to allocate buffer of size: %d.\n", length);
1748            return NULL;
1749        }
1750
1751        uprv_strcpy(tmpGenlibFlagBuffer, flag);
1752
1753        offset = uprv_strlen(rm_cmd);
1754
1755        for (i = 0; i < (length - offset); i++) {
1756            flag[i] = tmpGenlibFlagBuffer[offset + i];
1757        }
1758
1759        /* Zero terminate the string */
1760        flag[i] = 0;
1761
1762        uprv_free(tmpGenlibFlagBuffer);
1763    }
1764
1765    flag = pkgDataFlags[BIR_FLAGS];
1766    length = uprv_strlen(pkgDataFlags[BIR_FLAGS]);
1767
1768    for (int32_t i = 0; i < length; i++) {
1769        if (flag[i] == MAP_FILE_EXT[count]) {
1770            if (count == 0) {
1771                start = i;
1772            }
1773            count++;
1774        } else {
1775            count = 0;
1776        }
1777
1778        if (count == uprv_strlen(MAP_FILE_EXT)) {
1779            break;
1780        }
1781    }
1782
1783    if (start >= 0) {
1784        int32_t index = 0;
1785        for (int32_t i = 0;;i++) {
1786            if (i == start) {
1787                for (int32_t n = 0;;n++) {
1788                    if (o->shortName[n] == 0) {
1789                        break;
1790                    }
1791                    tmpbuffer[index++] = o->shortName[n];
1792                }
1793            }
1794
1795            tmpbuffer[index++] = flag[i];
1796
1797            if (flag[i] == 0) {
1798                break;
1799            }
1800        }
1801
1802        uprv_memset(flag, 0, length);
1803        uprv_strcpy(flag, tmpbuffer);
1804
1805        uprv_strcpy(mapFile, o->shortName);
1806        uprv_strcat(mapFile, MAP_FILE_EXT);
1807
1808        f = T_FileStream_open(mapFile, "w");
1809        if (f == NULL) {
1810            fprintf(stderr,"Unable to create map file: %s.\n", mapFile);
1811            return NULL;
1812        } else {
1813            sprintf(tmpbuffer, "%s%s ", o->entryName, UDATA_CMN_INTERMEDIATE_SUFFIX);
1814
1815            T_FileStream_writeLine(f, tmpbuffer);
1816
1817            T_FileStream_close(f);
1818        }
1819    }
1820#elif U_PLATFORM == U_PF_CYGWIN || U_PLATFORM == U_PF_MINGW
1821    /* Cygwin needs to change flag options. */
1822    char *flag = NULL;
1823    int32_t length = 0;
1824
1825    flag = pkgDataFlags[GENLIB];
1826    length = uprv_strlen(pkgDataFlags[GENLIB]);
1827
1828    int32_t position = length - 1;
1829
1830    for(;position >= 0;position--) {
1831        if (flag[position] == '=') {
1832            position++;
1833            break;
1834        }
1835    }
1836
1837    uprv_memset(flag + position, 0, length - position);
1838#elif U_PLATFORM == U_PF_OS400
1839    /* OS/400 needs to fix the ld options (swap single quote with double quote) */
1840    char *flag = NULL;
1841    int32_t length = 0;
1842
1843    flag = pkgDataFlags[GENLIB];
1844    length = uprv_strlen(pkgDataFlags[GENLIB]);
1845
1846    int32_t position = length - 1;
1847
1848    for(int32_t i = 0; i < length; i++) {
1849        if (flag[i] == '\'') {
1850            flag[i] = '\"';
1851        }
1852    }
1853#endif
1854    // Don't really need a return value, just need to stop compiler warnings about
1855    // the unused parameter 'o' on platforms where it is not otherwise used.
1856    return o;
1857}
1858
1859static void loadLists(UPKGOptions *o, UErrorCode *status)
1860{
1861    CharList   *l, *tail = NULL, *tail2 = NULL;
1862    FileStream *in;
1863    char        line[16384];
1864    char       *linePtr, *lineNext;
1865    const uint32_t   lineMax = 16300;
1866    char       *tmp;
1867    int32_t     tmpLength = 0;
1868    char       *s;
1869    int32_t     ln=0; /* line number */
1870
1871    for(l = o->fileListFiles; l; l = l->next) {
1872        if(o->verbose) {
1873            fprintf(stdout, "# pkgdata: Reading %s..\n", l->str);
1874        }
1875        /* TODO: stdin */
1876        in = T_FileStream_open(l->str, "r"); /* open files list */
1877
1878        if(!in) {
1879            fprintf(stderr, "Error opening <%s>.\n", l->str);
1880            *status = U_FILE_ACCESS_ERROR;
1881            return;
1882        }
1883
1884        while(T_FileStream_readLine(in, line, sizeof(line))!=NULL) { /* for each line */
1885            ln++;
1886            if(uprv_strlen(line)>lineMax) {
1887                fprintf(stderr, "%s:%d - line too long (over %d chars)\n", l->str, (int)ln, (int)lineMax);
1888                exit(1);
1889            }
1890            /* remove spaces at the beginning */
1891            linePtr = line;
1892            /* On z/OS, disable call to isspace (#9996).  Investigate using uprv_isspace instead (#9999) */
1893#if U_PLATFORM != U_PF_OS390
1894            while(isspace(*linePtr)) {
1895                linePtr++;
1896            }
1897#endif
1898            s=linePtr;
1899            /* remove trailing newline characters */
1900            while(*s!=0) {
1901                if(*s=='\r' || *s=='\n') {
1902                    *s=0;
1903                    break;
1904                }
1905                ++s;
1906            }
1907            if((*linePtr == 0) || (*linePtr == '#')) {
1908                continue; /* comment or empty line */
1909            }
1910
1911            /* Now, process the line */
1912            lineNext = NULL;
1913
1914            while(linePtr && *linePtr) { /* process space-separated items */
1915                while(*linePtr == ' ') {
1916                    linePtr++;
1917                }
1918                /* Find the next quote */
1919                if(linePtr[0] == '"')
1920                {
1921                    lineNext = uprv_strchr(linePtr+1, '"');
1922                    if(lineNext == NULL) {
1923                        fprintf(stderr, "%s:%d - missing trailing double quote (\")\n",
1924                            l->str, (int)ln);
1925                        exit(1);
1926                    } else {
1927                        lineNext++;
1928                        if(*lineNext) {
1929                            if(*lineNext != ' ') {
1930                                fprintf(stderr, "%s:%d - malformed quoted line at position %d, expected ' ' got '%c'\n",
1931                                    l->str, (int)ln, (int)(lineNext-line), (*lineNext)?*lineNext:'0');
1932                                exit(1);
1933                            }
1934                            *lineNext = 0;
1935                            lineNext++;
1936                        }
1937                    }
1938                } else {
1939                    lineNext = uprv_strchr(linePtr, ' ');
1940                    if(lineNext) {
1941                        *lineNext = 0; /* terminate at space */
1942                        lineNext++;
1943                    }
1944                }
1945
1946                /* add the file */
1947                s = (char*)getLongPathname(linePtr);
1948
1949                /* normal mode.. o->files is just the bare list without package names */
1950                o->files = pkg_appendToList(o->files, &tail, uprv_strdup(linePtr));
1951                if(uprv_pathIsAbsolute(s) || s[0] == '.') {
1952                    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);
1953                    exit(U_ILLEGAL_ARGUMENT_ERROR);
1954                }
1955                tmpLength = uprv_strlen(o->srcDir) +
1956                            uprv_strlen(s) + 5; /* 5 is to add a little extra space for, among other things, PKGDATA_FILE_SEP_STRING */
1957                if((tmp = (char *)uprv_malloc(tmpLength)) == NULL) {
1958                    fprintf(stderr, "pkgdata: Error: Unable to allocate tmp buffer size: %d\n", tmpLength);
1959                    exit(U_MEMORY_ALLOCATION_ERROR);
1960                }
1961                uprv_strcpy(tmp, o->srcDir);
1962                uprv_strcat(tmp, o->srcDir[uprv_strlen(o->srcDir)-1] == U_FILE_SEP_CHAR ? "" : PKGDATA_FILE_SEP_STRING);
1963                uprv_strcat(tmp, s);
1964                o->filePaths = pkg_appendToList(o->filePaths, &tail2, tmp);
1965                linePtr = lineNext;
1966            } /* for each entry on line */
1967        } /* for each line */
1968        T_FileStream_close(in);
1969    } /* for each file list file */
1970}
1971
1972/* Try calling icu-config directly to get the option file. */
1973 static int32_t pkg_getOptionsFromICUConfig(UBool verbose, UOption *option) {
1974#if U_HAVE_POPEN
1975    FILE *p = NULL;
1976    size_t n;
1977    static char buf[512] = "";
1978    char cmdBuf[1024];
1979    UErrorCode status = U_ZERO_ERROR;
1980    const char cmd[] = "icu-config --incpkgdatafile";
1981
1982    /* #1 try the same path where pkgdata was called from. */
1983    findDirname(progname, cmdBuf, 1024, &status);
1984    if(U_SUCCESS(status)) {
1985      if (cmdBuf[0] != 0) {
1986          uprv_strncat(cmdBuf, U_FILE_SEP_STRING, 1024);
1987      }
1988      uprv_strncat(cmdBuf, cmd, 1024);
1989
1990      if(verbose) {
1991        fprintf(stdout, "# Calling icu-config: %s\n", cmdBuf);
1992      }
1993      p = popen(cmdBuf, "r");
1994    }
1995
1996    if(p == NULL || (n = fread(buf, 1, 511, p)) <= 0) {
1997      if(verbose) {
1998        fprintf(stdout, "# Calling icu-config: %s\n", cmd);
1999      }
2000      pclose(p);
2001
2002      p = popen(cmd, "r");
2003      if(p == NULL || (n = fread(buf, 1, 511, p)) <= 0) {
2004          fprintf(stderr, "%s: icu-config: No icu-config found. (fix PATH or use -O option)\n", progname);
2005          return -1;
2006      }
2007    }
2008
2009    pclose(p);
2010
2011    for (int32_t length = strlen(buf) - 1; length >= 0; length--) {
2012        if (buf[length] == '\n' || buf[length] == ' ') {
2013            buf[length] = 0;
2014        } else {
2015            break;
2016        }
2017    }
2018
2019    if(buf[strlen(buf)-1]=='\n')
2020    {
2021        buf[strlen(buf)-1]=0;
2022    }
2023
2024    if(buf[0] == 0)
2025    {
2026        fprintf(stderr, "%s: icu-config: invalid response from icu-config (fix PATH or use -O option)\n", progname);
2027        return -1;
2028    }
2029
2030    if(verbose) {
2031      fprintf(stdout, "# icu-config said: %s\n", buf);
2032    }
2033
2034    option->value = buf;
2035    option->doesOccur = TRUE;
2036
2037    return 0;
2038#else
2039    return -1;
2040#endif
2041}
2042