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