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