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