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