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