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