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