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