• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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