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