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