1 /******************************************************************************
2 * Copyright (C) 2000-2014, International Business Machines
3 * Corporation and others. All Rights Reserved.
4 *******************************************************************************
5 * file name: pkgdata.cpp
6 * encoding: ANSI X3.4 (1968)
7 * tab size: 8 (not used)
10 * created on: 2000may15
11 * created by: Steven \u24C7 Loomis
13 * This program packages the ICU data into different forms
14 * (DLL, common data, etc.)
17 // Defines _XOPEN_SOURCE for access to POSIX functions.
18 // Must be before any other #includes.
19 #include "uposixdefs.h"
21 #include "unicode/utypes.h"
23 #include "unicode/putil.h"
27 #if (U_PF_MINGW <= U_PLATFORM || U_PLATFORM <= U_PF_CYGWIN) && defined(__STRICT_ANSI__)
28 /* popen/pclose aren't defined in strict ANSI on Cygwin and MinGW */
29 #undef __STRICT_ANSI__
37 #include "unicode/uclean.h"
43 #include "pkg_gencmn.h"
44 #include "flagparser.h"
45 #include "filetools.h"
59 static void loadLists(UPKGOptions
*o
, UErrorCode
*status
);
61 static int32_t pkg_executeOptions(UPKGOptions
*o
);
63 #ifdef WINDOWS_WITH_MSVC
64 static int32_t pkg_createWindowsDLL(const char mode
, const char *gencFilePath
, UPKGOptions
*o
);
66 static int32_t pkg_createSymLinks(const char *targetDir
, UBool specialHandling
=FALSE
);
67 static int32_t pkg_installLibrary(const char *installDir
, const char *dir
, UBool noVersion
);
68 static int32_t pkg_installFileMode(const char *installDir
, const char *srcDir
, const char *fileListName
);
69 static int32_t pkg_installCommonMode(const char *installDir
, const char *fileName
);
71 #ifdef BUILD_DATA_WITHOUT_ASSEMBLY
72 static int32_t pkg_createWithoutAssemblyCode(UPKGOptions
*o
, const char *targetDir
, const char mode
);
75 static int32_t pkg_createWithAssemblyCode(const char *targetDir
, const char mode
, const char *gencFilePath
);
76 static int32_t pkg_generateLibraryFile(const char *targetDir
, const char mode
, const char *objectFile
, char *command
= NULL
, UBool specialHandling
=FALSE
);
77 static int32_t pkg_archiveLibrary(const char *targetDir
, const char *version
, UBool reverseExt
);
78 static void createFileNames(UPKGOptions
*o
, const char mode
, const char *version_major
, const char *version
, const char *libName
, const UBool reverseExt
, UBool noVersion
);
79 static int32_t initializePkgDataFlags(UPKGOptions
*o
);
81 static int32_t pkg_getOptionsFromICUConfig(UBool verbose
, UOption
*option
);
82 static int runCommand(const char* command
, UBool specialHandling
=FALSE
);
84 #define IN_COMMON_MODE(mode) (mode == 'a' || mode == 'c')
85 #define IN_DLL_MODE(mode) (mode == 'd' || mode == 'l')
86 #define IN_STATIC_MODE(mode) (mode == 's')
87 #define IN_FILES_MODE(mode) (mode == 'f')
112 /* This sets the modes that are available */
114 const char *name
, *alt_name
;
117 { "files", 0, "Uses raw data files (no effect). Installation copies all files to the target location." },
118 #if U_PLATFORM_HAS_WIN32_API
119 { "dll", "library", "Generates one common data file and one shared library, <package>.dll"},
120 { "common", "archive", "Generates just the common file, <package>.dat"},
121 { "static", "static", "Generates one statically linked library, " LIB_PREFIX
"<package>" UDATA_LIB_SUFFIX
}
123 #ifdef UDATA_SO_SUFFIX
124 { "dll", "library", "Generates one shared library, <package>" UDATA_SO_SUFFIX
},
126 { "common", "archive", "Generates one common data file, <package>.dat" },
127 { "static", "static", "Generates one statically linked library, " LIB_PREFIX
"<package>" UDATA_LIB_SUFFIX
}
131 static UOption options
[]={
132 /*00*/ UOPTION_DEF( "name", 'p', UOPT_REQUIRES_ARG
),
133 /*01*/ UOPTION_DEF( "bldopt", 'O', UOPT_REQUIRES_ARG
), /* on Win32 it is release or debug */
134 /*02*/ UOPTION_DEF( "mode", 'm', UOPT_REQUIRES_ARG
),
135 /*03*/ UOPTION_HELP_H
, /* -h */
136 /*04*/ UOPTION_HELP_QUESTION_MARK
, /* -? */
137 /*05*/ UOPTION_VERBOSE
, /* -v */
138 /*06*/ UOPTION_COPYRIGHT
, /* -c */
139 /*07*/ UOPTION_DEF( "comment", 'C', UOPT_REQUIRES_ARG
),
140 /*08*/ UOPTION_DESTDIR
, /* -d */
141 /*11*/ UOPTION_DEF( "rebuild", 'F', UOPT_NO_ARG
),
142 /*12*/ UOPTION_DEF( "tempdir", 'T', UOPT_REQUIRES_ARG
),
143 /*13*/ UOPTION_DEF( "install", 'I', UOPT_REQUIRES_ARG
),
144 /*14*/ UOPTION_SOURCEDIR
,
145 /*15*/ UOPTION_DEF( "entrypoint", 'e', UOPT_REQUIRES_ARG
),
146 /*16*/ UOPTION_DEF( "revision", 'r', UOPT_REQUIRES_ARG
),
147 /*17*/ UOPTION_DEF( "force-prefix", 'f', UOPT_NO_ARG
),
148 /*18*/ UOPTION_DEF( "libname", 'L', UOPT_REQUIRES_ARG
),
149 /*19*/ UOPTION_DEF( "quiet", 'q', UOPT_NO_ARG
),
150 /*20*/ UOPTION_DEF( "without-assembly", 'w', UOPT_NO_ARG
),
151 /*21*/ UOPTION_DEF( "zos-pds-build", 'z', UOPT_NO_ARG
)
154 /* This enum and the following char array should be kept in sync. */
156 GENCCODE_ASSEMBLY_TYPE
,
175 static const char* FLAG_NAMES
[PKGDATA_FLAGS_SIZE
] = {
176 "GENCCODE_ASSEMBLY_TYPE",
194 static char **pkgDataFlags
= NULL
;
198 LIB_FILE_VERSION_MAJOR
,
200 LIB_FILE_VERSION_TMP
,
201 #if U_PLATFORM == U_PF_CYGWIN
203 LIB_FILE_CYGWIN_VERSION
,
204 #elif U_PLATFORM == U_PF_MINGW
206 #elif U_PLATFORM == U_PF_OS390
207 LIB_FILE_OS390BATCH_MAJOR
,
208 LIB_FILE_OS390BATCH_VERSION
,
212 static char libFileNames
[LIB_FILENAMES_SIZE
][256];
214 static UPKGOptions
*pkg_checkFlag(UPKGOptions
*o
);
216 const char options_help
[][320]={
218 #ifdef U_MAKE_IS_NMAKE
219 "The directory where the ICU is located (e.g. <ICUROOT> which contains the bin directory)",
221 "Specify options for the builder.",
223 "Specify the mode of building (see below; default: common)",
226 "Make the output verbose",
227 "Use the standard ICU copyright",
228 "Use a custom comment (instead of the copyright)",
229 "Specify the destination directory for files",
230 "Force rebuilding of all data",
231 "Specify temporary dir (default: output dir)",
232 "Install the data (specify target)",
233 "Specify a custom source directory",
234 "Specify a custom entrypoint name (default: short name)",
235 "Specify a version when packaging in dll or static mode",
236 "Add package to all file names if not present",
237 "Library name to build (if different than package name)",
238 "Quite mode. (e.g. Do not output a readme file for static libraries)",
239 "Build the data without assembly code",
240 "Build PDS dataset (zOS build only)"
243 const char *progname
= "PKGDATA";
246 main(int argc
, char* argv
[]) {
248 /* FileStream *out; */
251 UBool needsHelp
= FALSE
;
252 UErrorCode status
= U_ZERO_ERROR
;
253 /* char tmp[1024]; */
257 U_MAIN_INIT_ARGS(argc
, argv
);
261 options
[MODE
].value
= "common";
263 /* read command line options */
264 argc
=u_parseArgs(argc
, argv
, sizeof(options
)/sizeof(options
[0]), options
);
266 /* error handling, printing usage message */
267 /* I've decided to simply print an error and quit. This tool has too
268 many options to just display them all of the time. */
270 if(options
[HELP
].doesOccur
|| options
[HELP_QUESTION_MARK
].doesOccur
) {
274 if(!needsHelp
&& argc
<0) {
276 "%s: error in command line argument \"%s\"\n",
279 fprintf(stderr
, "Run '%s --help' for help.\n", progname
);
284 #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN)
285 if(!options
[BLDOPT
].doesOccur
&& uprv_strcmp(options
[MODE
].value
, "common") != 0) {
286 if (pkg_getOptionsFromICUConfig(options
[VERBOSE
].doesOccur
, &options
[BLDOPT
]) != 0) {
287 fprintf(stderr
, " required parameter is missing: -O is required for static and shared builds.\n");
288 fprintf(stderr
, "Run '%s --help' for help.\n", progname
);
293 if(options
[BLDOPT
].doesOccur
) {
294 fprintf(stdout
, "Warning: You are using the -O option which is not needed for MSVC build on Windows.\n");
298 if(!options
[NAME
].doesOccur
) /* -O we already have - don't report it. */
300 fprintf(stderr
, " required parameter -p is missing \n");
301 fprintf(stderr
, "Run '%s --help' for help.\n", progname
);
307 "No input files specified.\n"
308 "Run '%s --help' for help.\n", progname
);
311 } /* end !needsHelp */
313 if(argc
<0 || needsHelp
) {
315 "usage: %s [-options] [-] [packageFile] \n"
316 "\tProduce packaged ICU data from the given list(s) of files.\n"
317 "\t'-' by itself means to read from stdin.\n"
318 "\tpackageFile is a text file containing the list of files to package.\n",
321 fprintf(stderr
, "\n options:\n");
322 for(i
=0;i
<(sizeof(options
)/sizeof(options
[0]));i
++) {
323 fprintf(stderr
, "%-5s -%c %s%-10s %s\n",
325 options
[i
].shortName
,
326 options
[i
].longName
? "or --" : " ",
327 options
[i
].longName
? options
[i
].longName
: "",
331 fprintf(stderr
, "modes: (-m option)\n");
332 for(i
=0;i
<(sizeof(modes
)/sizeof(modes
[0]));i
++) {
333 fprintf(stderr
, " %-9s ", modes
[i
].name
);
334 if (modes
[i
].alt_name
) {
335 fprintf(stderr
, "/ %-9s", modes
[i
].alt_name
);
337 fprintf(stderr
, " ");
339 fprintf(stderr
, " %s\n", modes
[i
].desc
);
344 /* OK, fill in the options struct */
345 uprv_memset(&o
, 0, sizeof(o
));
347 o
.mode
= options
[MODE
].value
;
348 o
.version
= options
[REVISION
].doesOccur
? options
[REVISION
].value
: 0;
350 o
.shortName
= options
[NAME
].value
;
352 int32_t len
= (int32_t)uprv_strlen(o
.shortName
);
356 cp
= csname
= (char *) uprv_malloc((len
+ 1 + 1) * sizeof(*o
.cShortName
));
357 if (*(sp
= o
.shortName
)) {
358 *cp
++ = isalpha(*sp
) ? * sp
: '_';
359 for (++sp
; *sp
; ++sp
) {
360 *cp
++ = isalnum(*sp
) ? *sp
: '_';
365 o
.cShortName
= csname
;
368 if(options
[LIBNAME
].doesOccur
) { /* get libname from shortname, or explicit -L parameter */
369 o
.libName
= options
[LIBNAME
].value
;
371 o
.libName
= o
.shortName
;
374 if(options
[QUIET
].doesOccur
) {
380 if(options
[PDS_BUILD
].doesOccur
) {
381 #if U_PLATFORM == U_PF_OS390
385 fprintf(stdout
, "Warning: You are using the -z option which only works on z/OS.\n");
392 o
.verbose
= options
[VERBOSE
].doesOccur
;
395 #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN) /* on UNIX, we'll just include the file... */
396 if (options
[BLDOPT
].doesOccur
) {
397 o
.options
= options
[BLDOPT
].value
;
402 if(options
[COPYRIGHT
].doesOccur
) {
403 o
.comment
= U_COPYRIGHT_STRING
;
404 } else if (options
[COMMENT
].doesOccur
) {
405 o
.comment
= options
[COMMENT
].value
;
408 if( options
[DESTDIR
].doesOccur
) {
409 o
.targetDir
= options
[DESTDIR
].value
;
411 o
.targetDir
= "."; /* cwd */
414 o
.rebuild
= options
[REBUILD
].doesOccur
;
416 if( options
[TEMPDIR
].doesOccur
) {
417 o
.tmpDir
= options
[TEMPDIR
].value
;
419 o
.tmpDir
= o
.targetDir
;
422 if( options
[INSTALL
].doesOccur
) {
423 o
.install
= options
[INSTALL
].value
;
428 if( options
[SOURCEDIR
].doesOccur
) {
429 o
.srcDir
= options
[SOURCEDIR
].value
;
434 if( options
[ENTRYPOINT
].doesOccur
) {
435 o
.entryName
= options
[ENTRYPOINT
].value
;
437 o
.entryName
= o
.cShortName
;
440 o
.withoutAssembly
= FALSE
;
441 if (options
[WITHOUT_ASSEMBLY
].doesOccur
) {
442 #ifndef BUILD_DATA_WITHOUT_ASSEMBLY
443 fprintf(stdout
, "Warning: You are using the option to build without assembly code which is not supported on this platform.\n");
444 fprintf(stdout
, "Warning: This option will be ignored.\n");
446 o
.withoutAssembly
= TRUE
;
450 /* OK options are set up. Now the file lists. */
452 for( n
=1; n
<argc
; n
++) {
453 o
.fileListFiles
= pkg_appendToList(o
.fileListFiles
, &tail
, uprv_strdup(argv
[n
]));
457 loadLists(&o
, &status
);
458 if( U_FAILURE(status
) ) {
459 fprintf(stderr
, "error loading input file lists: %s\n", u_errorName(status
));
463 result
= pkg_executeOptions(&o
);
465 if (pkgDataFlags
!= NULL
) {
466 for (n
= 0; n
< PKGDATA_FLAGS_SIZE
; n
++) {
467 if (pkgDataFlags
[n
] != NULL
) {
468 uprv_free(pkgDataFlags
[n
]);
471 uprv_free(pkgDataFlags
);
474 if (o
.cShortName
!= NULL
) {
475 uprv_free((char *)o
.cShortName
);
477 if (o
.fileListFiles
!= NULL
) {
478 pkg_deleteList(o
.fileListFiles
);
480 if (o
.filePaths
!= NULL
) {
481 pkg_deleteList(o
.filePaths
);
483 if (o
.files
!= NULL
) {
484 pkg_deleteList(o
.files
);
490 static int runCommand(const char* command
, UBool specialHandling
) {
492 char cmdBuffer
[SMALL_BUFFER_MAX_SIZE
];
493 int32_t len
= strlen(command
);
499 if (!specialHandling
) {
500 #if defined(USING_CYGWIN) || U_PLATFORM == U_PF_MINGW || U_PLATFORM == U_PF_OS400
501 if ((len
+ BUFFER_PADDING_SIZE
) >= SMALL_BUFFER_MAX_SIZE
) {
502 cmd
= (char *)uprv_malloc(len
+ BUFFER_PADDING_SIZE
);
506 #if defined(USING_CYGWIN) || U_PLATFORM == U_PF_MINGW
507 sprintf(cmd
, "bash -c \"%s\"", command
);
509 #elif U_PLATFORM == U_PF_OS400
510 sprintf(cmd
, "QSH CMD('%s')", command
);
513 goto normal_command_mode
;
516 #if !(defined(USING_CYGWIN) || U_PLATFORM == U_PF_MINGW || U_PLATFORM == U_PF_OS400)
519 cmd
= (char *)command
;
522 printf("pkgdata: %s\n", cmd
);
523 int result
= system(cmd
);
525 fprintf(stderr
, "-- return status = %d\n", result
);
528 if (cmd
!= cmdBuffer
&& cmd
!= command
) {
535 #define LN_CMD "ln -s"
536 #define RM_CMD "rm -f"
538 static int32_t pkg_executeOptions(UPKGOptions
*o
) {
541 const char mode
= o
->mode
[0];
542 char targetDir
[SMALL_BUFFER_MAX_SIZE
] = "";
543 char tmpDir
[SMALL_BUFFER_MAX_SIZE
] = "";
544 char datFileName
[SMALL_BUFFER_MAX_SIZE
] = "";
545 char datFileNamePath
[LARGE_BUFFER_MAX_SIZE
] = "";
546 char checkLibFile
[LARGE_BUFFER_MAX_SIZE
] = "";
548 initializePkgDataFlags(o
);
550 if (IN_FILES_MODE(mode
)) {
551 /* Copy the raw data to the installation directory. */
552 if (o
->install
!= NULL
) {
553 uprv_strcpy(targetDir
, o
->install
);
554 if (o
->shortName
!= NULL
) {
555 uprv_strcat(targetDir
, PKGDATA_FILE_SEP_STRING
);
556 uprv_strcat(targetDir
, o
->shortName
);
560 fprintf(stdout
, "# Install: Files mode, copying files to %s..\n", targetDir
);
562 result
= pkg_installFileMode(targetDir
, o
->srcDir
, o
->fileListFiles
->str
);
565 } else /* if (IN_COMMON_MODE(mode) || IN_DLL_MODE(mode) || IN_STATIC_MODE(mode)) */ {
566 UBool noVersion
= FALSE
;
568 uprv_strcpy(targetDir
, o
->targetDir
);
569 uprv_strcat(targetDir
, PKGDATA_FILE_SEP_STRING
);
571 uprv_strcpy(tmpDir
, o
->tmpDir
);
572 uprv_strcat(tmpDir
, PKGDATA_FILE_SEP_STRING
);
574 uprv_strcpy(datFileNamePath
, tmpDir
);
576 uprv_strcpy(datFileName
, o
->shortName
);
577 uprv_strcat(datFileName
, UDATA_CMN_SUFFIX
);
579 uprv_strcat(datFileNamePath
, datFileName
);
582 fprintf(stdout
, "# Writing package file %s ..\n", datFileNamePath
);
584 result
= writePackageDatFile(datFileNamePath
, o
->comment
, o
->srcDir
, o
->fileListFiles
->str
, NULL
, U_CHARSET_FAMILY
? 'e' : U_IS_BIG_ENDIAN
? 'b' : 'l');
586 fprintf(stderr
,"Error writing package dat file.\n");
590 if (IN_COMMON_MODE(mode
)) {
591 char targetFileNamePath
[LARGE_BUFFER_MAX_SIZE
] = "";
593 uprv_strcpy(targetFileNamePath
, targetDir
);
594 uprv_strcat(targetFileNamePath
, datFileName
);
596 /* Move the dat file created to the target directory. */
597 if (uprv_strcmp(datFileNamePath
, targetFileNamePath
) != 0) {
598 if (T_FileStream_file_exists(targetFileNamePath
)) {
599 if ((result
= remove(targetFileNamePath
)) != 0) {
600 fprintf(stderr
, "Unable to remove old dat file: %s\n",
606 result
= rename(datFileNamePath
, targetFileNamePath
);
609 fprintf(stdout
, "# Moving package file to %s ..\n",
615 "Unable to move dat file (%s) to target location (%s).\n",
616 datFileNamePath
, targetFileNamePath
);
621 if (o
->install
!= NULL
) {
622 result
= pkg_installCommonMode(o
->install
, targetFileNamePath
);
626 } else /* if (IN_STATIC_MODE(mode) || IN_DLL_MODE(mode)) */ {
627 char gencFilePath
[SMALL_BUFFER_MAX_SIZE
] = "";
628 char version_major
[10] = "";
629 UBool reverseExt
= FALSE
;
631 #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN)
632 /* Get the version major number. */
633 if (o
->version
!= NULL
) {
634 for (uint32_t i
= 0;i
< sizeof(version_major
);i
++) {
635 if (o
->version
[i
] == '.') {
636 version_major
[i
] = 0;
639 version_major
[i
] = o
->version
[i
];
643 if (IN_DLL_MODE(mode
)) {
644 fprintf(stdout
, "Warning: Providing a revision number with the -r option is recommended when packaging data in the current mode.\n");
648 #if U_PLATFORM != U_PF_OS400
649 /* Certain platforms have different library extension ordering. (e.g. libicudata.##.so vs libicudata.so.##)
650 * reverseExt is FALSE if the suffix should be the version number.
652 if (pkgDataFlags
[LIB_EXT_ORDER
][uprv_strlen(pkgDataFlags
[LIB_EXT_ORDER
])-1] == pkgDataFlags
[SO_EXT
][uprv_strlen(pkgDataFlags
[SO_EXT
])-1]) {
656 /* Using the base libName and version number, generate the library file names. */
657 createFileNames(o
, mode
, version_major
, o
->version
== NULL
? "" : o
->version
, o
->libName
, reverseExt
, noVersion
);
659 if ((o
->version
!=NULL
|| IN_STATIC_MODE(mode
)) && o
->rebuild
== FALSE
&& o
->pdsbuild
== FALSE
) {
660 /* Check to see if a previous built data library file exists and check if it is the latest. */
661 sprintf(checkLibFile
, "%s%s", targetDir
, libFileNames
[LIB_FILE_VERSION
]);
662 if (T_FileStream_file_exists(checkLibFile
)) {
663 if (isFileModTimeLater(checkLibFile
, o
->srcDir
, TRUE
) && isFileModTimeLater(checkLibFile
, o
->options
)) {
664 if (o
->install
!= NULL
) {
666 fprintf(stdout
, "# Installing already-built library into %s\n", o
->install
);
668 result
= pkg_installLibrary(o
->install
, targetDir
, noVersion
);
671 printf("# Not rebuilding %s - up to date.\n", checkLibFile
);
675 } else if (o
->verbose
&& (o
->install
!=NULL
)) {
676 fprintf(stdout
, "# Not installing up-to-date library %s into %s\n", checkLibFile
, o
->install
);
678 } else if(o
->verbose
&& (o
->install
!=NULL
)) {
679 fprintf(stdout
, "# Not installing missing %s into %s\n", checkLibFile
, o
->install
);
683 if (pkg_checkFlag(o
) == NULL
) {
684 /* Error occurred. */
689 if (!o
->withoutAssembly
&& pkgDataFlags
[GENCCODE_ASSEMBLY_TYPE
][0] != 0) {
690 const char* genccodeAssembly
= pkgDataFlags
[GENCCODE_ASSEMBLY_TYPE
];
693 fprintf(stdout
, "# Generating assembly code %s of type %s ..\n", gencFilePath
, genccodeAssembly
);
696 /* Offset genccodeAssembly by 3 because "-a " */
697 if (genccodeAssembly
&&
698 (uprv_strlen(genccodeAssembly
)>3) &&
699 checkAssemblyHeaderName(genccodeAssembly
+3)) {
700 writeAssemblyCode(datFileNamePath
, o
->tmpDir
, o
->entryName
, NULL
, gencFilePath
);
702 result
= pkg_createWithAssemblyCode(targetDir
, mode
, gencFilePath
);
704 fprintf(stderr
, "Error generating assembly code for data.\n");
706 } else if (IN_STATIC_MODE(mode
)) {
707 if(o
->install
!= NULL
) {
709 fprintf(stdout
, "# Installing static library into %s\n", o
->install
);
711 result
= pkg_installLibrary(o
->install
, targetDir
, noVersion
);
716 fprintf(stderr
,"Assembly type \"%s\" is unknown.\n", genccodeAssembly
);
721 fprintf(stdout
, "# Writing object code to %s ..\n", gencFilePath
);
723 if (o
->withoutAssembly
) {
724 #ifdef BUILD_DATA_WITHOUT_ASSEMBLY
725 result
= pkg_createWithoutAssemblyCode(o
, targetDir
, mode
);
727 /* This error should not occur. */
728 fprintf(stderr
, "Error- BUILD_DATA_WITHOUT_ASSEMBLY is not defined. Internal error.\n");
731 #ifdef CAN_WRITE_OBJ_CODE
732 writeObjectCode(datFileNamePath
, o
->tmpDir
, o
->entryName
, NULL
, NULL
, gencFilePath
);
733 #if U_PLATFORM_IS_LINUX_BASED
734 result
= pkg_generateLibraryFile(targetDir
, mode
, gencFilePath
);
735 #elif defined(WINDOWS_WITH_MSVC)
736 result
= pkg_createWindowsDLL(mode
, gencFilePath
, o
);
738 #elif defined(BUILD_DATA_WITHOUT_ASSEMBLY)
739 result
= pkg_createWithoutAssemblyCode(o
, targetDir
, mode
);
741 fprintf(stderr
, "Error- neither CAN_WRITE_OBJ_CODE nor BUILD_DATA_WITHOUT_ASSEMBLY are defined. Internal error.\n");
747 fprintf(stderr
, "Error generating package data.\n");
751 #if !U_PLATFORM_USES_ONLY_WIN32_API
752 if(!IN_STATIC_MODE(mode
)) {
753 /* Certain platforms uses archive library. (e.g. AIX) */
755 fprintf(stdout
, "# Creating data archive library file ..\n");
757 result
= pkg_archiveLibrary(targetDir
, o
->version
, reverseExt
);
759 fprintf(stderr
, "Error creating data archive library file.\n");
762 #if U_PLATFORM != U_PF_OS400
764 /* Create symbolic links for the final library file. */
765 #if U_PLATFORM == U_PF_OS390
766 result
= pkg_createSymLinks(targetDir
, o
->pdsbuild
);
768 result
= pkg_createSymLinks(targetDir
, noVersion
);
771 fprintf(stderr
, "Error creating symbolic links of the data library file.\n");
776 } /* !IN_STATIC_MODE */
779 #if !U_PLATFORM_USES_ONLY_WIN32_API
780 /* Install the libraries if option was set. */
781 if (o
->install
!= NULL
) {
783 fprintf(stdout
, "# Installing library file to %s ..\n", o
->install
);
785 result
= pkg_installLibrary(o
->install
, targetDir
, noVersion
);
787 fprintf(stderr
, "Error installing the data library.\n");
797 /* Initialize the pkgDataFlags with the option file given. */
798 static int32_t initializePkgDataFlags(UPKGOptions
*o
) {
799 UErrorCode status
= U_ZERO_ERROR
;
801 int32_t currentBufferSize
= SMALL_BUFFER_MAX_SIZE
;
802 int32_t tmpResult
= 0;
804 /* Initialize pkgdataFlags */
805 pkgDataFlags
= (char**)uprv_malloc(sizeof(char*) * PKGDATA_FLAGS_SIZE
);
807 /* If we run out of space, allocate more */
808 #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN)
811 if (pkgDataFlags
!= NULL
) {
812 for (int32_t i
= 0; i
< PKGDATA_FLAGS_SIZE
; i
++) {
813 pkgDataFlags
[i
] = (char*)uprv_malloc(sizeof(char) * currentBufferSize
);
814 if (pkgDataFlags
[i
] != NULL
) {
815 pkgDataFlags
[i
][0] = 0;
817 fprintf(stderr
,"Error allocating memory for pkgDataFlags.\n");
822 fprintf(stderr
,"Error allocating memory for pkgDataFlags.\n");
826 if (o
->options
== NULL
) {
830 #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN)
831 /* Read in options file. */
833 fprintf(stdout
, "# Reading options file %s\n", o
->options
);
835 status
= U_ZERO_ERROR
;
836 tmpResult
= parseFlagsFile(o
->options
, pkgDataFlags
, currentBufferSize
, FLAG_NAMES
, (int32_t)PKGDATA_FLAGS_SIZE
, &status
);
837 if (status
== U_BUFFER_OVERFLOW_ERROR
) {
838 for (int32_t i
= 0; i
< PKGDATA_FLAGS_SIZE
; i
++) {
839 uprv_free(pkgDataFlags
[i
]);
841 currentBufferSize
= tmpResult
;
842 } else if (U_FAILURE(status
)) {
843 fprintf(stderr
,"Unable to open or read \"%s\" option file. status = %s\n", o
->options
, u_errorName(status
));
848 fprintf(stdout
, "# pkgDataFlags=\n");
849 for(int32_t i
=0;i
<PKGDATA_FLAGS_SIZE
;i
++) {
850 fprintf(stdout
, " [%d] %s: %s\n", i
, FLAG_NAMES
[i
], pkgDataFlags
[i
]);
852 fprintf(stdout
, "\n");
854 #if !defined(WINDOWS_WITH_MSVC) || defined(USING_CYGWIN)
855 } while (status
== U_BUFFER_OVERFLOW_ERROR
);
863 * Given the base libName and version numbers, generate the libary file names and store it in libFileNames.
864 * Depending on the configuration, the library name may either end with version number or shared object suffix.
866 static void createFileNames(UPKGOptions
*o
, const char mode
, const char *version_major
, const char *version
, const char *libName
, UBool reverseExt
, UBool noVersion
) {
867 #if U_PLATFORM == U_PF_MINGW
868 /* MinGW does not need the library prefix when building in dll mode. */
869 if (IN_DLL_MODE(mode
)) {
870 sprintf(libFileNames
[LIB_FILE
], "%s", libName
);
872 sprintf(libFileNames
[LIB_FILE
], "%s%s",
873 pkgDataFlags
[LIBPREFIX
],
877 sprintf(libFileNames
[LIB_FILE
], "%s%s",
878 pkgDataFlags
[LIBPREFIX
],
883 fprintf(stdout
, "# libFileName[LIB_FILE] = %s\n", libFileNames
[LIB_FILE
]);
886 #if U_PLATFORM == U_PF_MINGW
887 sprintf(libFileNames
[LIB_FILE_MINGW
], "%s%s.lib", pkgDataFlags
[LIBPREFIX
], libName
);
888 #elif U_PLATFORM == U_PF_CYGWIN
889 sprintf(libFileNames
[LIB_FILE_CYGWIN
], "cyg%s.%s",
891 pkgDataFlags
[SO_EXT
]);
892 sprintf(libFileNames
[LIB_FILE_CYGWIN_VERSION
], "cyg%s%s.%s",
895 pkgDataFlags
[SO_EXT
]);
897 uprv_strcat(pkgDataFlags
[SO_EXT
], ".");
898 uprv_strcat(pkgDataFlags
[SO_EXT
], pkgDataFlags
[A_EXT
]);
899 #elif U_PLATFORM == U_PF_OS400 || defined(_AIX)
900 sprintf(libFileNames
[LIB_FILE_VERSION_TMP
], "%s.%s",
901 libFileNames
[LIB_FILE
],
902 pkgDataFlags
[SOBJ_EXT
]);
903 #elif U_PLATFORM == U_PF_OS390
904 sprintf(libFileNames
[LIB_FILE_VERSION_TMP
], "%s%s%s.%s",
905 libFileNames
[LIB_FILE
],
906 pkgDataFlags
[LIB_EXT_ORDER
][0] == '.' ? "." : "",
907 reverseExt
? version
: pkgDataFlags
[SOBJ_EXT
],
908 reverseExt
? pkgDataFlags
[SOBJ_EXT
] : version
);
910 sprintf(libFileNames
[LIB_FILE_OS390BATCH_VERSION
], "%s%s.x",
911 libFileNames
[LIB_FILE
],
913 sprintf(libFileNames
[LIB_FILE_OS390BATCH_MAJOR
], "%s%s.x",
914 libFileNames
[LIB_FILE
],
917 if (noVersion
&& !reverseExt
) {
918 sprintf(libFileNames
[LIB_FILE_VERSION_TMP
], "%s%s%s",
919 libFileNames
[LIB_FILE
],
920 pkgDataFlags
[LIB_EXT_ORDER
][0] == '.' ? "." : "",
921 pkgDataFlags
[SOBJ_EXT
]);
923 sprintf(libFileNames
[LIB_FILE_VERSION_TMP
], "%s%s%s.%s",
924 libFileNames
[LIB_FILE
],
925 pkgDataFlags
[LIB_EXT_ORDER
][0] == '.' ? "." : "",
926 reverseExt
? version
: pkgDataFlags
[SOBJ_EXT
],
927 reverseExt
? pkgDataFlags
[SOBJ_EXT
] : version
);
930 if (noVersion
&& !reverseExt
) {
931 sprintf(libFileNames
[LIB_FILE_VERSION_MAJOR
], "%s%s%s",
932 libFileNames
[LIB_FILE
],
933 pkgDataFlags
[LIB_EXT_ORDER
][0] == '.' ? "." : "",
934 pkgDataFlags
[SO_EXT
]);
936 sprintf(libFileNames
[LIB_FILE_VERSION
], "%s%s%s",
937 libFileNames
[LIB_FILE
],
938 pkgDataFlags
[LIB_EXT_ORDER
][0] == '.' ? "." : "",
939 pkgDataFlags
[SO_EXT
]);
941 sprintf(libFileNames
[LIB_FILE_VERSION_MAJOR
], "%s%s%s.%s",
942 libFileNames
[LIB_FILE
],
943 pkgDataFlags
[LIB_EXT_ORDER
][0] == '.' ? "." : "",
944 reverseExt
? version_major
: pkgDataFlags
[SO_EXT
],
945 reverseExt
? pkgDataFlags
[SO_EXT
] : version_major
);
947 sprintf(libFileNames
[LIB_FILE_VERSION
], "%s%s%s.%s",
948 libFileNames
[LIB_FILE
],
949 pkgDataFlags
[LIB_EXT_ORDER
][0] == '.' ? "." : "",
950 reverseExt
? version
: pkgDataFlags
[SO_EXT
],
951 reverseExt
? pkgDataFlags
[SO_EXT
] : version
);
955 fprintf(stdout
, "# libFileName[LIB_FILE_VERSION] = %s\n", libFileNames
[LIB_FILE_VERSION
]);
958 #if U_PF_MINGW <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
959 /* Cygwin and MinGW only deals with the version major number. */
960 uprv_strcpy(libFileNames
[LIB_FILE_VERSION_TMP
], libFileNames
[LIB_FILE_VERSION_MAJOR
]);
963 if(IN_STATIC_MODE(mode
)) {
964 sprintf(libFileNames
[LIB_FILE_VERSION
], "%s.%s", libFileNames
[LIB_FILE
], pkgDataFlags
[A_EXT
]);
965 libFileNames
[LIB_FILE_VERSION_MAJOR
][0]=0;
967 fprintf(stdout
, "# libFileName[LIB_FILE_VERSION] = %s (static)\n", libFileNames
[LIB_FILE_VERSION
]);
972 /* Create the symbolic links for the final library file. */
973 static int32_t pkg_createSymLinks(const char *targetDir
, UBool specialHandling
) {
975 char cmd
[LARGE_BUFFER_MAX_SIZE
];
976 char name1
[SMALL_BUFFER_MAX_SIZE
]; /* symlink file name */
977 char name2
[SMALL_BUFFER_MAX_SIZE
]; /* file name to symlink */
979 #if !defined(USING_CYGWIN) && U_PLATFORM != U_PF_MINGW
980 /* No symbolic link to make. */
981 if (uprv_strlen(libFileNames
[LIB_FILE_VERSION
]) == 0 || uprv_strlen(libFileNames
[LIB_FILE_VERSION_MAJOR
]) == 0 ||
982 uprv_strcmp(libFileNames
[LIB_FILE_VERSION
], libFileNames
[LIB_FILE_VERSION_MAJOR
]) == 0) {
986 sprintf(cmd
, "cd %s && %s %s && %s %s %s",
989 libFileNames
[LIB_FILE_VERSION_MAJOR
],
991 libFileNames
[LIB_FILE_VERSION
],
992 libFileNames
[LIB_FILE_VERSION_MAJOR
]);
993 result
= runCommand(cmd
);
995 fprintf(stderr
, "Error creating symbolic links. Failed command: %s\n", cmd
);
1000 if (specialHandling
) {
1001 #if U_PLATFORM == U_PF_CYGWIN
1002 sprintf(name1
, "%s", libFileNames
[LIB_FILE_CYGWIN
]);
1003 sprintf(name2
, "%s", libFileNames
[LIB_FILE_CYGWIN_VERSION
]);
1004 #elif U_PLATFORM == U_PF_OS390
1005 /* Create the symbolic links for the import data */
1006 /* Use the cmd buffer to store path to import data file to check its existence */
1007 sprintf(cmd
, "%s/%s", targetDir
, libFileNames
[LIB_FILE_OS390BATCH_VERSION
]);
1008 if (T_FileStream_file_exists(cmd
)) {
1009 sprintf(cmd
, "cd %s && %s %s && %s %s %s",
1012 libFileNames
[LIB_FILE_OS390BATCH_MAJOR
],
1014 libFileNames
[LIB_FILE_OS390BATCH_VERSION
],
1015 libFileNames
[LIB_FILE_OS390BATCH_MAJOR
]);
1016 result
= runCommand(cmd
);
1018 fprintf(stderr
, "Error creating symbolic links. Failed command: %s\n", cmd
);
1022 sprintf(cmd
, "cd %s && %s %s.x && %s %s %s.x",
1025 libFileNames
[LIB_FILE
],
1027 libFileNames
[LIB_FILE_OS390BATCH_VERSION
],
1028 libFileNames
[LIB_FILE
]);
1029 result
= runCommand(cmd
);
1031 fprintf(stderr
, "Error creating symbolic links. Failed command: %s\n", cmd
);
1036 /* Needs to be set here because special handling skips it */
1037 sprintf(name1
, "%s.%s", libFileNames
[LIB_FILE
], pkgDataFlags
[SO_EXT
]);
1038 sprintf(name2
, "%s", libFileNames
[LIB_FILE_VERSION
]);
1040 goto normal_symlink_mode
;
1043 #if U_PLATFORM != U_PF_CYGWIN
1044 normal_symlink_mode
:
1046 sprintf(name1
, "%s.%s", libFileNames
[LIB_FILE
], pkgDataFlags
[SO_EXT
]);
1047 sprintf(name2
, "%s", libFileNames
[LIB_FILE_VERSION
]);
1050 sprintf(cmd
, "cd %s && %s %s && %s %s %s",
1058 result
= runCommand(cmd
);
1063 static int32_t pkg_installLibrary(const char *installDir
, const char *targetDir
, UBool noVersion
) {
1065 char cmd
[SMALL_BUFFER_MAX_SIZE
];
1067 sprintf(cmd
, "cd %s && %s %s %s%s%s",
1069 pkgDataFlags
[INSTALL_CMD
],
1070 libFileNames
[LIB_FILE_VERSION
],
1071 installDir
, PKGDATA_FILE_SEP_STRING
, libFileNames
[LIB_FILE_VERSION
]
1074 result
= runCommand(cmd
);
1077 fprintf(stderr
, "Error installing library. Failed command: %s\n", cmd
);
1082 sprintf(cmd
, "cd %s && %s %s.lib %s",
1084 pkgDataFlags
[INSTALL_CMD
],
1085 libFileNames
[LIB_FILE
],
1088 result
= runCommand(cmd
);
1091 fprintf(stderr
, "Error installing library. Failed command: %s\n", cmd
);
1094 #elif U_PLATFORM == U_PF_CYGWIN
1095 sprintf(cmd
, "cd %s && %s %s %s",
1097 pkgDataFlags
[INSTALL_CMD
],
1098 libFileNames
[LIB_FILE_CYGWIN_VERSION
],
1101 result
= runCommand(cmd
);
1104 fprintf(stderr
, "Error installing library. Failed command: %s\n", cmd
);
1108 #elif U_PLATFORM == U_PF_OS390
1109 if (T_FileStream_file_exists(libFileNames
[LIB_FILE_OS390BATCH_VERSION
])) {
1110 sprintf(cmd
, "%s %s %s",
1111 pkgDataFlags
[INSTALL_CMD
],
1112 libFileNames
[LIB_FILE_OS390BATCH_VERSION
],
1115 result
= runCommand(cmd
);
1118 fprintf(stderr
, "Error installing library. Failed command: %s\n", cmd
);
1127 return pkg_createSymLinks(installDir
, TRUE
);
1131 static int32_t pkg_installCommonMode(const char *installDir
, const char *fileName
) {
1133 char cmd
[SMALL_BUFFER_MAX_SIZE
] = "";
1135 if (!T_FileStream_file_exists(installDir
)) {
1136 UErrorCode status
= U_ZERO_ERROR
;
1138 uprv_mkdir(installDir
, &status
);
1139 if (U_FAILURE(status
)) {
1140 fprintf(stderr
, "Error creating installation directory: %s\n", installDir
);
1144 #ifndef U_WINDOWS_WITH_MSVC
1145 sprintf(cmd
, "%s %s %s", pkgDataFlags
[INSTALL_CMD
], fileName
, installDir
);
1147 sprintf(cmd
, "%s %s %s %s", WIN_INSTALL_CMD
, fileName
, installDir
, WIN_INSTALL_CMD_FLAGS
);
1150 result
= runCommand(cmd
);
1152 fprintf(stderr
, "Failed to install data file with command: %s\n", cmd
);
1158 #ifdef U_WINDOWS_MSVC
1159 /* Copy commands for installing the raw data files on Windows. */
1160 #define WIN_INSTALL_CMD "xcopy"
1161 #define WIN_INSTALL_CMD_FLAGS "/E /Y /K"
1163 static int32_t pkg_installFileMode(const char *installDir
, const char *srcDir
, const char *fileListName
) {
1165 char cmd
[SMALL_BUFFER_MAX_SIZE
] = "";
1167 if (!T_FileStream_file_exists(installDir
)) {
1168 UErrorCode status
= U_ZERO_ERROR
;
1170 uprv_mkdir(installDir
, &status
);
1171 if (U_FAILURE(status
)) {
1172 fprintf(stderr
, "Error creating installation directory: %s\n", installDir
);
1176 #ifndef U_WINDOWS_WITH_MSVC
1177 char buffer
[SMALL_BUFFER_MAX_SIZE
] = "";
1178 int32_t bufferLength
= 0;
1180 FileStream
*f
= T_FileStream_open(fileListName
, "r");
1183 if (T_FileStream_readLine(f
, buffer
, SMALL_BUFFER_MAX_SIZE
) != NULL
) {
1184 bufferLength
= uprv_strlen(buffer
);
1185 /* Remove new line character. */
1186 if (bufferLength
> 0) {
1187 buffer
[bufferLength
-1] = 0;
1190 sprintf(cmd
, "%s %s%s%s %s%s%s",
1191 pkgDataFlags
[INSTALL_CMD
],
1192 srcDir
, PKGDATA_FILE_SEP_STRING
, buffer
,
1193 installDir
, PKGDATA_FILE_SEP_STRING
, buffer
);
1195 result
= runCommand(cmd
);
1197 fprintf(stderr
, "Failed to install data file with command: %s\n", cmd
);
1201 if (!T_FileStream_eof(f
)) {
1202 fprintf(stderr
, "Failed to read line from file: %s\n", fileListName
);
1208 T_FileStream_close(f
);
1211 fprintf(stderr
, "Unable to open list file: %s\n", fileListName
);
1214 sprintf(cmd
, "%s %s %s %s", WIN_INSTALL_CMD
, srcDir
, installDir
, WIN_INSTALL_CMD_FLAGS
);
1215 result
= runCommand(cmd
);
1217 fprintf(stderr
, "Failed to install data file with command: %s\n", cmd
);
1224 /* Archiving of the library file may be needed depending on the platform and options given.
1225 * If archiving is not needed, copy over the library file name.
1227 static int32_t pkg_archiveLibrary(const char *targetDir
, const char *version
, UBool reverseExt
) {
1229 char cmd
[LARGE_BUFFER_MAX_SIZE
];
1231 /* If the shared object suffix and the final object suffix is different and the final object suffix and the
1232 * archive file suffix is the same, then the final library needs to be archived.
1234 if (uprv_strcmp(pkgDataFlags
[SOBJ_EXT
], pkgDataFlags
[SO_EXT
]) != 0 && uprv_strcmp(pkgDataFlags
[A_EXT
], pkgDataFlags
[SO_EXT
]) == 0) {
1235 sprintf(libFileNames
[LIB_FILE_VERSION
], "%s%s%s.%s",
1236 libFileNames
[LIB_FILE
],
1237 pkgDataFlags
[LIB_EXT_ORDER
][0] == '.' ? "." : "",
1238 reverseExt
? version
: pkgDataFlags
[SO_EXT
],
1239 reverseExt
? pkgDataFlags
[SO_EXT
] : version
);
1241 sprintf(cmd
, "%s %s %s%s %s%s",
1243 pkgDataFlags
[ARFLAGS
],
1245 libFileNames
[LIB_FILE_VERSION
],
1247 libFileNames
[LIB_FILE_VERSION_TMP
]);
1249 result
= runCommand(cmd
);
1251 fprintf(stderr
, "Error creating archive library. Failed command: %s\n", cmd
);
1255 sprintf(cmd
, "%s %s%s",
1256 pkgDataFlags
[RANLIB
],
1258 libFileNames
[LIB_FILE_VERSION
]);
1260 result
= runCommand(cmd
);
1262 fprintf(stderr
, "Error creating archive library. Failed command: %s\n", cmd
);
1266 /* Remove unneeded library file. */
1267 sprintf(cmd
, "%s %s%s",
1270 libFileNames
[LIB_FILE_VERSION_TMP
]);
1272 result
= runCommand(cmd
);
1274 fprintf(stderr
, "Error creating archive library. Failed command: %s\n", cmd
);
1279 uprv_strcpy(libFileNames
[LIB_FILE_VERSION
], libFileNames
[LIB_FILE_VERSION_TMP
]);
1286 * Using the compiler information from the configuration file set by -O option, generate the library file.
1287 * command may be given to allow for a larger buffer for cmd.
1289 static int32_t pkg_generateLibraryFile(const char *targetDir
, const char mode
, const char *objectFile
, char *command
, UBool specialHandling
) {
1292 UBool freeCmd
= FALSE
;
1295 /* This is necessary because if packaging is done without assembly code, objectFile might be extremely large
1296 * containing many object files and so the calling function should supply a command buffer that is large
1297 * enough to handle this. Otherwise, use the default size.
1299 if (command
!= NULL
) {
1303 if (IN_STATIC_MODE(mode
)) {
1305 length
= uprv_strlen(pkgDataFlags
[AR
]) + uprv_strlen(pkgDataFlags
[ARFLAGS
]) + uprv_strlen(targetDir
) +
1306 uprv_strlen(libFileNames
[LIB_FILE_VERSION
]) + uprv_strlen(objectFile
) + uprv_strlen(pkgDataFlags
[RANLIB
]) + BUFFER_PADDING_SIZE
;
1307 if ((cmd
= (char *)uprv_malloc(sizeof(char) * length
)) == NULL
) {
1308 fprintf(stderr
, "Unable to allocate memory for command.\n");
1313 sprintf(cmd
, "%s %s %s%s %s",
1315 pkgDataFlags
[ARFLAGS
],
1317 libFileNames
[LIB_FILE_VERSION
],
1320 result
= runCommand(cmd
);
1322 sprintf(cmd
, "%s %s%s",
1323 pkgDataFlags
[RANLIB
],
1325 libFileNames
[LIB_FILE_VERSION
]);
1327 result
= runCommand(cmd
);
1329 } else /* if (IN_DLL_MODE(mode)) */ {
1331 length
= uprv_strlen(pkgDataFlags
[GENLIB
]) + uprv_strlen(pkgDataFlags
[LDICUDTFLAGS
]) +
1332 ((uprv_strlen(targetDir
) + uprv_strlen(libFileNames
[LIB_FILE_VERSION_TMP
])) * 2) +
1333 uprv_strlen(objectFile
) + uprv_strlen(pkgDataFlags
[LD_SONAME
]) +
1334 uprv_strlen(pkgDataFlags
[LD_SONAME
][0] == 0 ? "" : libFileNames
[LIB_FILE_VERSION_MAJOR
]) +
1335 uprv_strlen(pkgDataFlags
[RPATH_FLAGS
]) + uprv_strlen(pkgDataFlags
[BIR_FLAGS
]) + BUFFER_PADDING_SIZE
;
1336 #if U_PLATFORM == U_PF_CYGWIN
1337 length
+= uprv_strlen(targetDir
) + uprv_strlen(libFileNames
[LIB_FILE_CYGWIN_VERSION
]);
1338 #elif U_PLATFORM == U_PF_MINGW
1339 length
+= uprv_strlen(targetDir
) + uprv_strlen(libFileNames
[LIB_FILE_MINGW
]);
1341 if ((cmd
= (char *)uprv_malloc(sizeof(char) * length
)) == NULL
) {
1342 fprintf(stderr
, "Unable to allocate memory for command.\n");
1347 #if U_PLATFORM == U_PF_MINGW
1348 sprintf(cmd
, "%s%s%s %s -o %s%s %s %s%s %s %s",
1349 pkgDataFlags
[GENLIB
],
1351 libFileNames
[LIB_FILE_MINGW
],
1352 pkgDataFlags
[LDICUDTFLAGS
],
1354 libFileNames
[LIB_FILE_VERSION_TMP
],
1355 #elif U_PLATFORM == U_PF_CYGWIN
1356 sprintf(cmd
, "%s%s%s %s -o %s%s %s %s%s %s %s",
1357 pkgDataFlags
[GENLIB
],
1359 libFileNames
[LIB_FILE_VERSION_TMP
],
1360 pkgDataFlags
[LDICUDTFLAGS
],
1362 libFileNames
[LIB_FILE_CYGWIN_VERSION
],
1363 #elif U_PLATFORM == U_PF_AIX
1364 sprintf(cmd
, "%s %s%s;%s %s -o %s%s %s %s%s %s %s",
1367 libFileNames
[LIB_FILE_VERSION_TMP
],
1368 pkgDataFlags
[GENLIB
],
1369 pkgDataFlags
[LDICUDTFLAGS
],
1371 libFileNames
[LIB_FILE_VERSION_TMP
],
1373 sprintf(cmd
, "%s %s -o %s%s %s %s%s %s %s",
1374 pkgDataFlags
[GENLIB
],
1375 pkgDataFlags
[LDICUDTFLAGS
],
1377 libFileNames
[LIB_FILE_VERSION_TMP
],
1380 pkgDataFlags
[LD_SONAME
],
1381 pkgDataFlags
[LD_SONAME
][0] == 0 ? "" : libFileNames
[LIB_FILE_VERSION_MAJOR
],
1382 pkgDataFlags
[RPATH_FLAGS
],
1383 pkgDataFlags
[BIR_FLAGS
]);
1385 /* Generate the library file. */
1386 result
= runCommand(cmd
);
1388 #if U_PLATFORM == U_PF_OS390
1390 char PDS_LibName
[512];
1395 if (specialHandling
&& uprv_strcmp(libFileNames
[LIB_FILE
],"libicudata") == 0) {
1396 if (env_tmp
= getenv("ICU_PDS_NAME")) {
1397 sprintf(PDS_Name
, "%s%s",
1400 strcat(PDS_Name
, getenv("ICU_PDS_NAME_SUFFIX"));
1401 } else if (env_tmp
= getenv("PDS_NAME_PREFIX")) {
1402 sprintf(PDS_Name
, "%s%s",
1404 U_ICU_VERSION_SHORT
"DA");
1406 sprintf(PDS_Name
, "%s%s",
1408 U_ICU_VERSION_SHORT
"DA");
1410 } else if (!specialHandling
&& uprv_strcmp(libFileNames
[LIB_FILE
],"libicudata_stub") == 0) {
1411 if (env_tmp
= getenv("ICU_PDS_NAME")) {
1412 sprintf(PDS_Name
, "%s%s",
1415 strcat(PDS_Name
, getenv("ICU_PDS_NAME_SUFFIX"));
1416 } else if (env_tmp
= getenv("PDS_NAME_PREFIX")) {
1417 sprintf(PDS_Name
, "%s%s",
1419 U_ICU_VERSION_SHORT
"D1");
1421 sprintf(PDS_Name
, "%s%s",
1423 U_ICU_VERSION_SHORT
"D1");
1428 sprintf(PDS_LibName
,"%s%s%s%s%s",
1434 sprintf(cmd
, "%s %s -o %s %s %s%s %s %s",
1435 pkgDataFlags
[GENLIB
],
1436 pkgDataFlags
[LDICUDTFLAGS
],
1439 pkgDataFlags
[LD_SONAME
],
1440 pkgDataFlags
[LD_SONAME
][0] == 0 ? "" : libFileNames
[LIB_FILE_VERSION_MAJOR
],
1441 pkgDataFlags
[RPATH_FLAGS
],
1442 pkgDataFlags
[BIR_FLAGS
]);
1444 result
= runCommand(cmd
);
1450 fprintf(stderr
, "Error generating library file. Failed command: %s\n", cmd
);
1460 static int32_t pkg_createWithAssemblyCode(const char *targetDir
, const char mode
, const char *gencFilePath
) {
1461 char tempObjectFile
[SMALL_BUFFER_MAX_SIZE
] = "";
1467 /* Remove the ending .s and replace it with .o for the new object file. */
1468 uprv_strcpy(tempObjectFile
, gencFilePath
);
1469 tempObjectFile
[uprv_strlen(tempObjectFile
)-1] = 'o';
1471 length
= uprv_strlen(pkgDataFlags
[COMPILER
]) + uprv_strlen(pkgDataFlags
[LIBFLAGS
])
1472 + uprv_strlen(tempObjectFile
) + uprv_strlen(gencFilePath
) + BUFFER_PADDING_SIZE
;
1474 cmd
= (char *)uprv_malloc(sizeof(char) * length
);
1479 /* Generate the object file. */
1480 sprintf(cmd
, "%s %s -o %s %s",
1481 pkgDataFlags
[COMPILER
],
1482 pkgDataFlags
[LIBFLAGS
],
1486 result
= runCommand(cmd
);
1489 fprintf(stderr
, "Error creating with assembly code. Failed command: %s\n", cmd
);
1493 return pkg_generateLibraryFile(targetDir
, mode
, tempObjectFile
);
1496 #ifdef BUILD_DATA_WITHOUT_ASSEMBLY
1498 * Generation of the data library without assembly code needs to compile each data file
1499 * individually and then link it all together.
1500 * Note: Any update to the directory structure of the data needs to be reflected here.
1509 DATA_PREFIX_TRANSLIT
,
1514 const static char DATA_PREFIX
[DATA_PREFIX_LENGTH
][10] = {
1525 static int32_t pkg_createWithoutAssemblyCode(UPKGOptions
*o
, const char *targetDir
, const char mode
) {
1527 CharList
*list
= o
->filePaths
;
1528 CharList
*listNames
= o
->files
;
1529 int32_t listSize
= pkg_countCharList(list
);
1532 char gencmnFile
[SMALL_BUFFER_MAX_SIZE
] = "";
1533 char tempObjectFile
[SMALL_BUFFER_MAX_SIZE
] = "";
1534 #ifdef USE_SINGLE_CCODE_FILE
1535 char icudtAll
[SMALL_BUFFER_MAX_SIZE
] = "";
1536 FileStream
*icudtAllFile
= NULL
;
1538 sprintf(icudtAll
, "%s%s%sall.c",
1540 PKGDATA_FILE_SEP_STRING
,
1541 libFileNames
[LIB_FILE
]);
1542 /* Remove previous icudtall.c file. */
1543 if (T_FileStream_file_exists(icudtAll
) && (result
= remove(icudtAll
)) != 0) {
1544 fprintf(stderr
, "Unable to remove old icudtall file: %s\n", icudtAll
);
1548 if((icudtAllFile
= T_FileStream_open(icudtAll
, "w"))==NULL
) {
1549 fprintf(stderr
, "Unable to write to icudtall file: %s\n", icudtAll
);
1554 if (list
== NULL
|| listNames
== NULL
) {
1555 /* list and listNames should never be NULL since we are looping through the CharList with
1561 if ((cmd
= (char *)uprv_malloc((listSize
+ 2) * SMALL_BUFFER_MAX_SIZE
)) == NULL
) {
1562 fprintf(stderr
, "Unable to allocate memory for cmd.\n");
1564 } else if ((buffer
= (char *)uprv_malloc((listSize
+ 1) * SMALL_BUFFER_MAX_SIZE
)) == NULL
) {
1565 fprintf(stderr
, "Unable to allocate memory for buffer.\n");
1570 for (int32_t i
= 0; i
< (listSize
+ 1); i
++) {
1575 /* The first iteration calls the gencmn function and initailizes the buffer. */
1576 createCommonDataFile(o
->tmpDir
, o
->shortName
, o
->entryName
, NULL
, o
->srcDir
, o
->comment
, o
->fileListFiles
->str
, 0, TRUE
, o
->verbose
, gencmnFile
);
1578 #ifdef USE_SINGLE_CCODE_FILE
1579 uprv_strcpy(tempObjectFile
, gencmnFile
);
1580 tempObjectFile
[uprv_strlen(tempObjectFile
) - 1] = 'o';
1582 sprintf(cmd
, "%s %s -o %s %s",
1583 pkgDataFlags
[COMPILER
],
1584 pkgDataFlags
[LIBFLAGS
],
1588 result
= runCommand(cmd
);
1593 sprintf(buffer
, "%s",tempObjectFile
);
1596 char newName
[SMALL_BUFFER_MAX_SIZE
];
1597 char dataName
[SMALL_BUFFER_MAX_SIZE
];
1598 char dataDirName
[SMALL_BUFFER_MAX_SIZE
];
1599 const char *pSubstring
;
1601 name
= listNames
->str
;
1603 newName
[0] = dataName
[0] = 0;
1604 for (int32_t n
= 0; n
< DATA_PREFIX_LENGTH
; n
++) {
1606 sprintf(dataDirName
, "%s%s", DATA_PREFIX
[n
], PKGDATA_FILE_SEP_STRING
);
1607 /* If the name contains a prefix (indicating directory), alter the new name accordingly. */
1608 pSubstring
= uprv_strstr(name
, dataDirName
);
1609 if (pSubstring
!= NULL
) {
1610 char newNameTmp
[SMALL_BUFFER_MAX_SIZE
] = "";
1611 const char *p
= name
+ uprv_strlen(dataDirName
);
1612 for (int32_t i
= 0;;i
++) {
1614 newNameTmp
[i
] = '_';
1617 newNameTmp
[i
] = p
[i
];
1622 sprintf(newName
, "%s_%s",
1625 sprintf(dataName
, "%s_%s",
1629 if (newName
[0] != 0) {
1635 printf("# Generating %s \n", gencmnFile
);
1638 writeCCode(file
, o
->tmpDir
, dataName
[0] != 0 ? dataName
: o
->shortName
, newName
[0] != 0 ? newName
: NULL
, gencmnFile
);
1640 #ifdef USE_SINGLE_CCODE_FILE
1641 sprintf(cmd
, "#include \"%s\"\n", gencmnFile
);
1642 T_FileStream_writeLine(icudtAllFile
, cmd
);
1643 /* don't delete the file */
1647 #ifndef USE_SINGLE_CCODE_FILE
1648 uprv_strcpy(tempObjectFile
, gencmnFile
);
1649 tempObjectFile
[uprv_strlen(tempObjectFile
) - 1] = 'o';
1651 sprintf(cmd
, "%s %s -o %s %s",
1652 pkgDataFlags
[COMPILER
],
1653 pkgDataFlags
[LIBFLAGS
],
1656 result
= runCommand(cmd
);
1658 fprintf(stderr
, "Error creating library without assembly code. Failed command: %s\n", cmd
);
1662 uprv_strcat(buffer
, " ");
1663 uprv_strcat(buffer
, tempObjectFile
);
1669 listNames
= listNames
->next
;
1673 #ifdef USE_SINGLE_CCODE_FILE
1674 T_FileStream_close(icudtAllFile
);
1675 uprv_strcpy(tempObjectFile
, icudtAll
);
1676 tempObjectFile
[uprv_strlen(tempObjectFile
) - 1] = 'o';
1678 sprintf(cmd
, "%s %s -I. -o %s %s",
1679 pkgDataFlags
[COMPILER
],
1680 pkgDataFlags
[LIBFLAGS
],
1684 result
= runCommand(cmd
);
1686 uprv_strcat(buffer
, " ");
1687 uprv_strcat(buffer
, tempObjectFile
);
1689 fprintf(stderr
, "Error creating library without assembly code. Failed command: %s\n", cmd
);
1694 /* Generate the library file. */
1695 #if U_PLATFORM == U_PF_OS390
1696 result
= pkg_generateLibraryFile(targetDir
, mode
, buffer
, cmd
, (o
->pdsbuild
&& IN_DLL_MODE(mode
)));
1698 result
= pkg_generateLibraryFile(targetDir
,mode
, buffer
, cmd
);
1709 #ifdef WINDOWS_WITH_MSVC
1710 #define LINK_CMD "link.exe /nologo /release /out:"
1711 #define LINK_FLAGS "/DLL /NOENTRY /MANIFEST:NO /base:0x4ad00000 /implib:"
1712 #define LIB_CMD "LIB.exe /nologo /out:"
1713 #define LIB_FILE "icudt.lib"
1714 #define LIB_EXT UDATA_LIB_SUFFIX
1715 #define DLL_EXT UDATA_SO_SUFFIX
1717 static int32_t pkg_createWindowsDLL(const char mode
, const char *gencFilePath
, UPKGOptions
*o
) {
1719 char cmd
[LARGE_BUFFER_MAX_SIZE
];
1720 if (IN_STATIC_MODE(mode
)) {
1721 char staticLibFilePath
[SMALL_BUFFER_MAX_SIZE
] = "";
1724 sprintf(staticLibFilePath
, "%s%s%s%s%s",
1726 PKGDATA_FILE_SEP_STRING
,
1727 pkgDataFlags
[LIBPREFIX
],
1731 sprintf(staticLibFilePath
, "%s%s%s%s%s",
1733 PKGDATA_FILE_SEP_STRING
,
1734 (strstr(o
->libName
, "icudt") ? "s" : ""),
1739 sprintf(cmd
, "%s\"%s\" \"%s\"",
1743 } else if (IN_DLL_MODE(mode
)) {
1744 char dllFilePath
[SMALL_BUFFER_MAX_SIZE
] = "";
1745 char libFilePath
[SMALL_BUFFER_MAX_SIZE
] = "";
1746 char resFilePath
[SMALL_BUFFER_MAX_SIZE
] = "";
1747 char tmpResFilePath
[SMALL_BUFFER_MAX_SIZE
] = "";
1750 uprv_strcpy(dllFilePath
, o
->targetDir
);
1752 uprv_strcpy(dllFilePath
, o
->srcDir
);
1754 uprv_strcat(dllFilePath
, PKGDATA_FILE_SEP_STRING
);
1755 uprv_strcpy(libFilePath
, dllFilePath
);
1758 uprv_strcat(libFilePath
, o
->libName
);
1759 uprv_strcat(libFilePath
, ".lib");
1761 uprv_strcat(dllFilePath
, o
->libName
);
1762 uprv_strcat(dllFilePath
, o
->version
);
1764 if (strstr(o
->libName
, "icudt")) {
1765 uprv_strcat(libFilePath
, LIB_FILE
);
1767 uprv_strcat(libFilePath
, o
->libName
);
1768 uprv_strcat(libFilePath
, ".lib");
1770 uprv_strcat(dllFilePath
, o
->entryName
);
1772 uprv_strcat(dllFilePath
, DLL_EXT
);
1774 uprv_strcpy(tmpResFilePath
, o
->tmpDir
);
1775 uprv_strcat(tmpResFilePath
, PKGDATA_FILE_SEP_STRING
);
1776 uprv_strcat(tmpResFilePath
, ICUDATA_RES_FILE
);
1778 if (T_FileStream_file_exists(tmpResFilePath
)) {
1779 sprintf(resFilePath
, "\"%s\"", tmpResFilePath
);
1782 /* Check if dll file and lib file exists and that it is not newer than genc file. */
1783 if (!o
->rebuild
&& (T_FileStream_file_exists(dllFilePath
) && isFileModTimeLater(dllFilePath
, gencFilePath
)) &&
1784 (T_FileStream_file_exists(libFilePath
) && isFileModTimeLater(libFilePath
, gencFilePath
))) {
1786 printf("# Not rebuilding %s - up to date.\n", gencFilePath
);
1791 sprintf(cmd
, "%s\"%s\" %s\"%s\" \"%s\" %s",
1801 result
= runCommand(cmd
, TRUE
);
1803 fprintf(stderr
, "Error creating Windows DLL library. Failed command: %s\n", cmd
);
1810 static UPKGOptions
*pkg_checkFlag(UPKGOptions
*o
) {
1811 #if U_PLATFORM == U_PF_AIX
1812 /* AIX needs a map file. */
1815 char tmpbuffer
[SMALL_BUFFER_MAX_SIZE
];
1816 const char MAP_FILE_EXT
[] = ".map";
1817 FileStream
*f
= NULL
;
1818 char mapFile
[SMALL_BUFFER_MAX_SIZE
] = "";
1821 const char rm_cmd
[] = "rm -f all ;";
1823 flag
= pkgDataFlags
[GENLIB
];
1825 /* This portion of the code removes 'rm -f all' in the GENLIB.
1826 * Only occurs in AIX.
1828 if (uprv_strstr(flag
, rm_cmd
) != NULL
) {
1829 char *tmpGenlibFlagBuffer
= NULL
;
1832 length
= uprv_strlen(flag
) + 1;
1833 tmpGenlibFlagBuffer
= (char *)uprv_malloc(length
);
1834 if (tmpGenlibFlagBuffer
== NULL
) {
1835 /* Memory allocation error */
1836 fprintf(stderr
,"Unable to allocate buffer of size: %d.\n", length
);
1840 uprv_strcpy(tmpGenlibFlagBuffer
, flag
);
1842 offset
= uprv_strlen(rm_cmd
);
1844 for (i
= 0; i
< (length
- offset
); i
++) {
1845 flag
[i
] = tmpGenlibFlagBuffer
[offset
+ i
];
1848 /* Zero terminate the string */
1851 uprv_free(tmpGenlibFlagBuffer
);
1854 flag
= pkgDataFlags
[BIR_FLAGS
];
1855 length
= uprv_strlen(pkgDataFlags
[BIR_FLAGS
]);
1857 for (int32_t i
= 0; i
< length
; i
++) {
1858 if (flag
[i
] == MAP_FILE_EXT
[count
]) {
1867 if (count
== uprv_strlen(MAP_FILE_EXT
)) {
1874 for (int32_t i
= 0;;i
++) {
1876 for (int32_t n
= 0;;n
++) {
1877 if (o
->shortName
[n
] == 0) {
1880 tmpbuffer
[index
++] = o
->shortName
[n
];
1884 tmpbuffer
[index
++] = flag
[i
];
1891 uprv_memset(flag
, 0, length
);
1892 uprv_strcpy(flag
, tmpbuffer
);
1894 uprv_strcpy(mapFile
, o
->shortName
);
1895 uprv_strcat(mapFile
, MAP_FILE_EXT
);
1897 f
= T_FileStream_open(mapFile
, "w");
1899 fprintf(stderr
,"Unable to create map file: %s.\n", mapFile
);
1902 sprintf(tmpbuffer
, "%s%s ", o
->entryName
, UDATA_CMN_INTERMEDIATE_SUFFIX
);
1904 T_FileStream_writeLine(f
, tmpbuffer
);
1906 T_FileStream_close(f
);
1909 #elif U_PLATFORM == U_PF_CYGWIN || U_PLATFORM == U_PF_MINGW
1910 /* Cygwin needs to change flag options. */
1914 flag
= pkgDataFlags
[GENLIB
];
1915 length
= uprv_strlen(pkgDataFlags
[GENLIB
]);
1917 int32_t position
= length
- 1;
1919 for(;position
>= 0;position
--) {
1920 if (flag
[position
] == '=') {
1926 uprv_memset(flag
+ position
, 0, length
- position
);
1927 #elif U_PLATFORM == U_PF_OS400
1928 /* OS/400 needs to fix the ld options (swap single quote with double quote) */
1932 flag
= pkgDataFlags
[GENLIB
];
1933 length
= uprv_strlen(pkgDataFlags
[GENLIB
]);
1935 int32_t position
= length
- 1;
1937 for(int32_t i
= 0; i
< length
; i
++) {
1938 if (flag
[i
] == '\'') {
1943 // Don't really need a return value, just need to stop compiler warnings about
1944 // the unused parameter 'o' on platforms where it is not otherwise used.
1948 static void loadLists(UPKGOptions
*o
, UErrorCode
*status
)
1950 CharList
*l
, *tail
= NULL
, *tail2
= NULL
;
1953 char *linePtr
, *lineNext
;
1954 const uint32_t lineMax
= 16300;
1956 int32_t tmpLength
= 0;
1958 int32_t ln
=0; /* line number */
1960 for(l
= o
->fileListFiles
; l
; l
= l
->next
) {
1962 fprintf(stdout
, "# pkgdata: Reading %s..\n", l
->str
);
1965 in
= T_FileStream_open(l
->str
, "r"); /* open files list */
1968 fprintf(stderr
, "Error opening <%s>.\n", l
->str
);
1969 *status
= U_FILE_ACCESS_ERROR
;
1973 while(T_FileStream_readLine(in
, line
, sizeof(line
))!=NULL
) { /* for each line */
1975 if(uprv_strlen(line
)>lineMax
) {
1976 fprintf(stderr
, "%s:%d - line too long (over %d chars)\n", l
->str
, (int)ln
, (int)lineMax
);
1979 /* remove spaces at the beginning */
1981 /* On z/OS, disable call to isspace (#9996). Investigate using uprv_isspace instead (#9999) */
1982 #if U_PLATFORM != U_PF_OS390
1983 while(isspace(*linePtr
)) {
1988 /* remove trailing newline characters */
1990 if(*s
=='\r' || *s
=='\n') {
1996 if((*linePtr
== 0) || (*linePtr
== '#')) {
1997 continue; /* comment or empty line */
2000 /* Now, process the line */
2003 while(linePtr
&& *linePtr
) { /* process space-separated items */
2004 while(*linePtr
== ' ') {
2007 /* Find the next quote */
2008 if(linePtr
[0] == '"')
2010 lineNext
= uprv_strchr(linePtr
+1, '"');
2011 if(lineNext
== NULL
) {
2012 fprintf(stderr
, "%s:%d - missing trailing double quote (\")\n",
2018 if(*lineNext
!= ' ') {
2019 fprintf(stderr
, "%s:%d - malformed quoted line at position %d, expected ' ' got '%c'\n",
2020 l
->str
, (int)ln
, (int)(lineNext
-line
), (*lineNext
)?*lineNext
:'0');
2028 lineNext
= uprv_strchr(linePtr
, ' ');
2030 *lineNext
= 0; /* terminate at space */
2036 s
= (char*)getLongPathname(linePtr
);
2038 /* normal mode.. o->files is just the bare list without package names */
2039 o
->files
= pkg_appendToList(o
->files
, &tail
, uprv_strdup(linePtr
));
2040 if(uprv_pathIsAbsolute(s
) || s
[0] == '.') {
2041 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
);
2042 exit(U_ILLEGAL_ARGUMENT_ERROR
);
2044 tmpLength
= uprv_strlen(o
->srcDir
) +
2045 uprv_strlen(s
) + 5; /* 5 is to add a little extra space for, among other things, PKGDATA_FILE_SEP_STRING */
2046 if((tmp
= (char *)uprv_malloc(tmpLength
)) == NULL
) {
2047 fprintf(stderr
, "pkgdata: Error: Unable to allocate tmp buffer size: %d\n", tmpLength
);
2048 exit(U_MEMORY_ALLOCATION_ERROR
);
2050 uprv_strcpy(tmp
, o
->srcDir
);
2051 uprv_strcat(tmp
, o
->srcDir
[uprv_strlen(o
->srcDir
)-1] == U_FILE_SEP_CHAR
? "" : PKGDATA_FILE_SEP_STRING
);
2052 uprv_strcat(tmp
, s
);
2053 o
->filePaths
= pkg_appendToList(o
->filePaths
, &tail2
, tmp
);
2055 } /* for each entry on line */
2056 } /* for each line */
2057 T_FileStream_close(in
);
2058 } /* for each file list file */
2061 /* Try calling icu-config directly to get the option file. */
2062 static int32_t pkg_getOptionsFromICUConfig(UBool verbose
, UOption
*option
) {
2066 static char buf
[512] = "";
2068 UErrorCode status
= U_ZERO_ERROR
;
2069 const char cmd
[] = "icu-config --incpkgdatafile";
2071 /* #1 try the same path where pkgdata was called from. */
2072 findDirname(progname
, cmdBuf
, 1024, &status
);
2073 if(U_SUCCESS(status
)) {
2074 if (cmdBuf
[0] != 0) {
2075 uprv_strncat(cmdBuf
, U_FILE_SEP_STRING
, 1024);
2077 uprv_strncat(cmdBuf
, cmd
, 1023);
2080 fprintf(stdout
, "# Calling icu-config: %s\n", cmdBuf
);
2082 p
= popen(cmdBuf
, "r");
2085 if(p
== NULL
|| (n
= fread(buf
, 1, 511, p
)) <= 0) {
2087 fprintf(stdout
, "# Calling icu-config: %s\n", cmd
);
2091 p
= popen(cmd
, "r");
2092 if(p
== NULL
|| (n
= fread(buf
, 1, 511, p
)) <= 0) {
2093 fprintf(stderr
, "%s: icu-config: No icu-config found. (fix PATH or use -O option)\n", progname
);
2100 for (int32_t length
= strlen(buf
) - 1; length
>= 0; length
--) {
2101 if (buf
[length
] == '\n' || buf
[length
] == ' ') {
2108 if(buf
[strlen(buf
)-1]=='\n')
2110 buf
[strlen(buf
)-1]=0;
2115 fprintf(stderr
, "%s: icu-config: invalid response from icu-config (fix PATH or use -O option)\n", progname
);
2120 fprintf(stdout
, "# icu-config said: %s\n", buf
);
2123 option
->value
= buf
;
2124 option
->doesOccur
= TRUE
;