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