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