]>
Commit | Line | Data |
---|---|---|
b75a7d8f A |
1 | /****************************************************************************** |
2 | * | |
73c04bcf | 3 | * Copyright (C) 2000-2006, International Business Machines |
b75a7d8f A |
4 | * Corporation and others. All Rights Reserved. |
5 | * | |
6 | ******************************************************************************* | |
7 | * file name: pkgdata.c | |
8 | * encoding: ANSI X3.4 (1968) | |
9 | * tab size: 8 (not used) | |
10 | * indentation:4 | |
11 | * | |
12 | * created on: 2000may15 | |
13 | * created by: Steven \u24C7 Loomis | |
14 | * | |
15 | * This program packages the ICU data into different forms | |
16 | * (DLL, common data, etc.) | |
17 | */ | |
18 | ||
b75a7d8f A |
19 | #include "unicode/utypes.h" |
20 | #include "unicode/putil.h" | |
21 | #include "cmemory.h" | |
22 | #include "cstring.h" | |
23 | #include "filestrm.h" | |
24 | #include "toolutil.h" | |
374ca955 | 25 | #include "unicode/uclean.h" |
b75a7d8f A |
26 | #include "unewdata.h" |
27 | #include "uoptions.h" | |
73c04bcf | 28 | #include "putilimp.h" |
b75a7d8f A |
29 | |
30 | #if U_HAVE_POPEN | |
374ca955 A |
31 | /* |
32 | We define __USE_POSIX2 so that we can get popen and pclose when | |
33 | --enable-strict is used | |
34 | */ | |
35 | # ifndef __USE_POSIX2 | |
36 | # define __USE_POSIX2 1 | |
37 | # endif | |
b75a7d8f A |
38 | # include <unistd.h> |
39 | #endif | |
374ca955 A |
40 | #include <stdio.h> |
41 | #include <stdlib.h> | |
b75a7d8f A |
42 | |
43 | U_CDECL_BEGIN | |
44 | #include "pkgtypes.h" | |
45 | #include "makefile.h" | |
46 | U_CDECL_END | |
47 | ||
48 | static int executeMakefile(const UPKGOptions *o); | |
49 | static void loadLists(UPKGOptions *o, UErrorCode *status); | |
50 | ||
51 | /* always have this fcn, just might not do anything */ | |
52 | static void fillInMakefileFromICUConfig(UOption *option); | |
53 | ||
54 | /* This sets the modes that are available */ | |
55 | static struct | |
56 | { | |
57 | const char *name, *alt_name; | |
58 | UPKGMODE *fcn; | |
59 | const char *desc; | |
60 | } modes[] = | |
61 | { | |
62 | { "files", 0, pkg_mode_files, "Uses raw data files (no effect). Installation copies all files to the target location." }, | |
374ca955 | 63 | #ifdef U_MAKE_IS_NMAKE |
b75a7d8f A |
64 | { "dll", "library", pkg_mode_windows, "Generates one common data file and one shared library, <package>.dll"}, |
65 | { "common", "archive", pkg_mode_windows, "Generates just the common file, <package>.dat"}, | |
66 | { "static", "static", pkg_mode_windows, "Generates one statically linked library, " LIB_PREFIX "<package>" UDATA_LIB_SUFFIX } | |
374ca955 | 67 | #else /*#ifdef U_MAKE_IS_NMAKE*/ |
b75a7d8f A |
68 | #ifdef UDATA_SO_SUFFIX |
69 | { "dll", "library", pkg_mode_dll, "Generates one shared library, <package>" UDATA_SO_SUFFIX }, | |
70 | #endif | |
71 | { "common", "archive", pkg_mode_common, "Generates one common data file, <package>.dat" }, | |
72 | { "static", "static", pkg_mode_static, "Generates one statically linked library, " LIB_PREFIX "<package>" UDATA_LIB_SUFFIX } | |
374ca955 | 73 | #endif /*#ifdef U_MAKE_IS_NMAKE*/ |
b75a7d8f A |
74 | }; |
75 | ||
73c04bcf A |
76 | enum { |
77 | NAME, | |
78 | BLDOPT, | |
79 | MODE, | |
80 | HELP, | |
81 | HELP_QUESTION_MARK, | |
82 | VERBOSE, | |
83 | COPYRIGHT, | |
84 | COMMENT, | |
85 | DESTDIR, | |
86 | CLEAN, | |
87 | NOOUTPUT, | |
88 | REBUILD, | |
89 | TEMPDIR, | |
90 | INSTALL, | |
91 | SOURCEDIR, | |
92 | ENTRYPOINT, | |
93 | REVISION, | |
94 | MAKEARG, | |
95 | FORCE_PREFIX, | |
96 | LIBNAME, | |
97 | QUIET | |
98 | }; | |
99 | ||
b75a7d8f A |
100 | static UOption options[]={ |
101 | /*00*/ UOPTION_DEF( "name", 'p', UOPT_REQUIRES_ARG), | |
102 | /*01*/ UOPTION_DEF( "bldopt", 'O', UOPT_REQUIRES_ARG), /* on Win32 it is release or debug */ | |
103 | /*02*/ UOPTION_DEF( "mode", 'm', UOPT_REQUIRES_ARG), | |
104 | /*03*/ UOPTION_HELP_H, /* -h */ | |
105 | /*04*/ UOPTION_HELP_QUESTION_MARK, /* -? */ | |
106 | /*05*/ UOPTION_VERBOSE, /* -v */ | |
107 | /*06*/ UOPTION_COPYRIGHT, /* -c */ | |
108 | /*07*/ UOPTION_DEF( "comment", 'C', UOPT_REQUIRES_ARG), | |
109 | /*08*/ UOPTION_DESTDIR, /* -d */ | |
110 | /*09*/ UOPTION_DEF( "clean", 'k', UOPT_NO_ARG), | |
111 | /*10*/ UOPTION_DEF( "nooutput",'n', UOPT_NO_ARG), | |
112 | /*11*/ UOPTION_DEF( "rebuild", 'F', UOPT_NO_ARG), | |
113 | /*12*/ UOPTION_DEF( "tempdir", 'T', UOPT_REQUIRES_ARG), | |
114 | /*13*/ UOPTION_DEF( "install", 'I', UOPT_REQUIRES_ARG), | |
115 | /*14*/ UOPTION_SOURCEDIR , | |
116 | /*15*/ UOPTION_DEF( "entrypoint", 'e', UOPT_REQUIRES_ARG), | |
117 | /*16*/ UOPTION_DEF( "revision", 'r', UOPT_REQUIRES_ARG), | |
73c04bcf | 118 | /*17*/ UOPTION_DEF( "makearg", 'M', UOPT_REQUIRES_ARG), |
374ca955 | 119 | /*18*/ UOPTION_DEF( "force-prefix", 'f', UOPT_NO_ARG), |
73c04bcf A |
120 | /*19*/ UOPTION_DEF( "libname", 'L', UOPT_REQUIRES_ARG), |
121 | /*20*/ UOPTION_DEF( "quiet", 'q', UOPT_NO_ARG) | |
b75a7d8f A |
122 | }; |
123 | ||
374ca955 | 124 | const char options_help[][320]={ |
b75a7d8f | 125 | "Set the data name", |
374ca955 A |
126 | #ifdef U_MAKE_IS_NMAKE |
127 | "The directory where the ICU is located (e.g. <ICUROOT> which contains the bin directory)", | |
b75a7d8f A |
128 | #else |
129 | "Specify options for the builder. (Autdetected if icu-config is available)", | |
130 | #endif | |
131 | "Specify the mode of building (see below; default: common)", | |
132 | "This usage text", | |
133 | "This usage text", | |
134 | "Make the output verbose", | |
135 | "Use the standard ICU copyright", | |
136 | "Use a custom comment (instead of the copyright)", | |
137 | "Specify the destination directory for files", | |
138 | "Clean out generated & temporary files", | |
139 | "Suppress output of data, just list files to be created", | |
140 | "Force rebuilding of all data", | |
141 | "Specify temporary dir (default: output dir)", | |
142 | "Install the data (specify target)", | |
143 | "Specify a custom source directory", | |
144 | "Specify a custom entrypoint name (default: short name)", | |
145 | "Specify a version when packaging in DLL or static mode", | |
146 | "Pass the next argument to make(1)", | |
374ca955 | 147 | "Add package to all file names if not present", |
374ca955 A |
148 | "Library name to build (if different than package name)", |
149 | "Quite mode. (e.g. Do not output a readme file for static libraries)" | |
b75a7d8f A |
150 | }; |
151 | ||
152 | const char *progname = "PKGDATA"; | |
153 | ||
154 | int | |
155 | main(int argc, char* argv[]) { | |
156 | FileStream *out; | |
157 | UPKGOptions o; | |
158 | CharList *tail; | |
159 | UBool needsHelp = FALSE; | |
160 | UErrorCode status = U_ZERO_ERROR; | |
161 | char tmp[1024]; | |
162 | int32_t i; | |
163 | ||
164 | U_MAIN_INIT_ARGS(argc, argv); | |
165 | ||
166 | progname = argv[0]; | |
167 | ||
73c04bcf A |
168 | options[MODE].value = "common"; |
169 | options[MAKEARG].value = ""; | |
b75a7d8f A |
170 | |
171 | /* read command line options */ | |
172 | argc=u_parseArgs(argc, argv, sizeof(options)/sizeof(options[0]), options); | |
173 | ||
174 | /* error handling, printing usage message */ | |
175 | /* I've decided to simply print an error and quit. This tool has too | |
176 | many options to just display them all of the time. */ | |
177 | ||
73c04bcf | 178 | if(options[HELP].doesOccur || options[HELP_QUESTION_MARK].doesOccur) { |
b75a7d8f A |
179 | needsHelp = TRUE; |
180 | } | |
181 | else { | |
182 | if(!needsHelp && argc<0) { | |
183 | fprintf(stderr, | |
184 | "%s: error in command line argument \"%s\"\n", | |
185 | progname, | |
186 | argv[-argc]); | |
187 | fprintf(stderr, "Run '%s --help' for help.\n", progname); | |
188 | return 1; | |
189 | } | |
190 | ||
73c04bcf | 191 | if(!options[BLDOPT].doesOccur) { |
374ca955 A |
192 | /* Try to fill in from icu-config or equivalent */ |
193 | fillInMakefileFromICUConfig(&options[1]); | |
194 | } | |
195 | #ifdef U_MAKE_IS_NMAKE | |
196 | else { | |
197 | fprintf(stderr, "Warning: You are using the deprecated -O option\n" | |
198 | "\tYou can fix this warning by installing pkgdata, gencmn and genccode\n" | |
199 | "\tinto the same directory and not specifying the -O option to pkgdata.\n"); | |
b75a7d8f | 200 | } |
374ca955 | 201 | #endif |
b75a7d8f | 202 | |
73c04bcf | 203 | if(!options[BLDOPT].doesOccur) { |
374ca955 A |
204 | fprintf(stderr, " required parameter is missing: -O is required \n"); |
205 | fprintf(stderr, "Run '%s --help' for help.\n", progname); | |
206 | return 1; | |
b75a7d8f | 207 | } |
374ca955 | 208 | |
73c04bcf | 209 | if(!options[NAME].doesOccur) /* -O we already have - don't report it. */ |
b75a7d8f | 210 | { |
374ca955 A |
211 | fprintf(stderr, " required parameter -p is missing \n"); |
212 | fprintf(stderr, "Run '%s --help' for help.\n", progname); | |
213 | return 1; | |
b75a7d8f A |
214 | } |
215 | ||
216 | if(argc == 1) { | |
217 | fprintf(stderr, | |
218 | "No input files specified.\n" | |
219 | "Run '%s --help' for help.\n", progname); | |
220 | return 1; | |
221 | } | |
222 | } /* end !needsHelp */ | |
223 | ||
224 | if(argc<0 || needsHelp ) { | |
225 | fprintf(stderr, | |
226 | "usage: %s [-options] [-] [packageFile] \n" | |
227 | "\tProduce packaged ICU data from the given list(s) of files.\n" | |
228 | "\t'-' by itself means to read from stdin.\n" | |
229 | "\tpackageFile is a text file containing the list of files to package.\n", | |
230 | progname); | |
231 | ||
232 | fprintf(stderr, "\n options:\n"); | |
233 | for(i=0;i<(sizeof(options)/sizeof(options[0]));i++) { | |
234 | fprintf(stderr, "%-5s -%c %s%-10s %s\n", | |
374ca955 | 235 | (i<1?"[REQ]":""), |
b75a7d8f A |
236 | options[i].shortName, |
237 | options[i].longName ? "or --" : " ", | |
238 | options[i].longName ? options[i].longName : "", | |
239 | options_help[i]); | |
240 | } | |
241 | ||
242 | fprintf(stderr, "modes: (-m option)\n"); | |
243 | for(i=0;i<(sizeof(modes)/sizeof(modes[0]));i++) { | |
244 | fprintf(stderr, " %-9s ", modes[i].name); | |
245 | if (modes[i].alt_name) { | |
246 | fprintf(stderr, "/ %-9s", modes[i].alt_name); | |
247 | } else { | |
248 | fprintf(stderr, " "); | |
249 | } | |
250 | fprintf(stderr, " %s\n", modes[i].desc); | |
251 | } | |
252 | return 1; | |
253 | } | |
254 | ||
255 | /* OK, fill in the options struct */ | |
256 | uprv_memset(&o, 0, sizeof(o)); | |
257 | ||
73c04bcf A |
258 | o.mode = options[MODE].value; |
259 | o.version = options[REVISION].doesOccur ? options[REVISION].value : 0; | |
260 | o.makeArgs = options[MAKEARG].value; | |
b75a7d8f A |
261 | |
262 | o.fcn = NULL; | |
263 | ||
264 | for(i=0;i<sizeof(modes)/sizeof(modes[0]);i++) { | |
265 | if(!uprv_strcmp(modes[i].name, o.mode)) { | |
266 | o.fcn = modes[i].fcn; | |
267 | break; | |
268 | } else if (modes[i].alt_name && !uprv_strcmp(modes[i].alt_name, o.mode)) { | |
269 | o.mode = modes[i].name; | |
270 | o.fcn = modes[i].fcn; | |
271 | break; | |
272 | } | |
273 | } | |
274 | ||
275 | if(o.fcn == NULL) { | |
276 | fprintf(stderr, "Error: invalid mode '%s' specified. Run '%s --help' to list valid modes.\n", o.mode, progname); | |
277 | return 1; | |
278 | } | |
279 | ||
280 | o.shortName = options[0].value; | |
374ca955 A |
281 | { |
282 | int32_t len = (int32_t)uprv_strlen(o.shortName); | |
b75a7d8f A |
283 | char *csname, *cp; |
284 | const char *sp; | |
285 | ||
286 | cp = csname = (char *) uprv_malloc((len + 1 + 1) * sizeof(*o.cShortName)); | |
287 | if (*(sp = o.shortName)) { | |
288 | *cp++ = isalpha(*sp) ? * sp : '_'; | |
289 | for (++sp; *sp; ++sp) { | |
290 | *cp++ = isalnum(*sp) ? *sp : '_'; | |
291 | } | |
292 | } | |
293 | *cp = 0; | |
294 | ||
295 | o.cShortName = csname; | |
296 | } | |
297 | ||
73c04bcf A |
298 | if(options[LIBNAME].doesOccur) { /* get libname from shortname, or explicit -L parameter */ |
299 | o.libName = options[LIBNAME].value; | |
374ca955 A |
300 | } else { |
301 | o.libName = o.shortName; | |
302 | } | |
303 | ||
73c04bcf | 304 | if(options[QUIET].doesOccur) { |
374ca955 A |
305 | o.quiet = TRUE; |
306 | } else { | |
307 | o.quiet = FALSE; | |
308 | } | |
309 | ||
73c04bcf | 310 | o.verbose = options[VERBOSE].doesOccur; |
374ca955 | 311 | #ifdef U_MAKE_IS_NMAKE /* format is R:pathtoICU or D:pathtoICU */ |
b75a7d8f | 312 | { |
73c04bcf A |
313 | char *pathstuff = (char *)options[BLDOPT].value; |
314 | if(options[1].value[uprv_strlen(options[BLDOPT].value)-1] == '\\') { | |
315 | pathstuff[uprv_strlen(options[BLDOPT].value)-1] = '\0'; | |
b75a7d8f | 316 | } |
374ca955 | 317 | if(*pathstuff == PKGDATA_DERIVED_PATH || *pathstuff == 'R' || *pathstuff == 'D') { |
b75a7d8f A |
318 | o.options = pathstuff; |
319 | pathstuff++; | |
320 | if(*pathstuff == ':') { | |
321 | *pathstuff = '\0'; | |
322 | pathstuff++; | |
374ca955 A |
323 | } |
324 | else { | |
325 | fprintf(stderr, "Error: invalid windows build mode, should be R (release) or D (debug).\n"); | |
b75a7d8f A |
326 | return 1; |
327 | } | |
328 | } else { | |
374ca955 | 329 | fprintf(stderr, "Error: invalid windows build mode, should be R (release) or D (debug).\n"); |
b75a7d8f A |
330 | return 1; |
331 | } | |
332 | o.icuroot = pathstuff; | |
374ca955 A |
333 | if (o.verbose) { |
334 | fprintf(stdout, "# ICUROOT is %s\n", o.icuroot); | |
335 | } | |
b75a7d8f A |
336 | } |
337 | #else /* on UNIX, we'll just include the file... */ | |
73c04bcf | 338 | o.options = options[BLDOPT].value; |
b75a7d8f | 339 | #endif |
73c04bcf | 340 | if(options[COPYRIGHT].doesOccur) { |
b75a7d8f | 341 | o.comment = U_COPYRIGHT_STRING; |
73c04bcf A |
342 | } else if (options[COMMENT].doesOccur) { |
343 | o.comment = options[COMMENT].value; | |
b75a7d8f A |
344 | } |
345 | ||
73c04bcf A |
346 | if( options[DESTDIR].doesOccur ) { |
347 | o.targetDir = options[DESTDIR].value; | |
b75a7d8f A |
348 | } else { |
349 | o.targetDir = "."; /* cwd */ | |
350 | } | |
351 | ||
73c04bcf A |
352 | o.clean = options[CLEAN].doesOccur; |
353 | o.nooutput = options[NOOUTPUT].doesOccur; | |
354 | o.rebuild = options[REBUILD].doesOccur; | |
374ca955 | 355 | |
73c04bcf A |
356 | if( options[TEMPDIR].doesOccur ) { |
357 | o.tmpDir = options[TEMPDIR].value; | |
b75a7d8f A |
358 | } else { |
359 | o.tmpDir = o.targetDir; | |
360 | } | |
361 | ||
73c04bcf A |
362 | if( options[INSTALL].doesOccur ) { |
363 | o.install = options[INSTALL].value; | |
b75a7d8f A |
364 | } |
365 | ||
73c04bcf A |
366 | if( options[SOURCEDIR].doesOccur ) { |
367 | o.srcDir = options[SOURCEDIR].value; | |
b75a7d8f A |
368 | } else { |
369 | o.srcDir = "."; | |
370 | } | |
371 | ||
73c04bcf A |
372 | if( options[ENTRYPOINT].doesOccur ) { |
373 | o.entryName = options[ENTRYPOINT].value; | |
b75a7d8f A |
374 | } else { |
375 | o.entryName = o.cShortName; | |
376 | } | |
377 | ||
378 | /* OK options are set up. Now the file lists. */ | |
379 | tail = NULL; | |
380 | for( i=1; i<argc; i++) { | |
381 | if ( !uprv_strcmp(argv[i] , "-") ) { | |
382 | /* stdin */ | |
383 | if( o.hadStdin == TRUE ) { | |
384 | fprintf(stderr, "Error: can't specify '-' twice!\n" | |
385 | "Run '%s --help' for help.\n", progname); | |
386 | return 1; | |
387 | } | |
388 | o.hadStdin = TRUE; | |
389 | } | |
390 | ||
391 | o.fileListFiles = pkg_appendToList(o.fileListFiles, &tail, uprv_strdup(argv[i])); | |
392 | } | |
393 | ||
394 | /* load the files */ | |
395 | loadLists(&o, &status); | |
396 | if( U_FAILURE(status) ) { | |
397 | fprintf(stderr, "error loading input file lists: %s\n", u_errorName(status)); | |
398 | return 2; | |
399 | } | |
400 | ||
401 | /* Makefile pathname */ | |
402 | uprv_strcpy(tmp, o.tmpDir); | |
73c04bcf | 403 | #ifdef U_MAKE_IS_NMAKE |
b75a7d8f | 404 | uprv_strcat(tmp, U_FILE_SEP_STRING); |
73c04bcf A |
405 | #else |
406 | uprv_strcat(tmp, U_FILE_ALT_SEP_STRING); | |
407 | #endif | |
b75a7d8f A |
408 | uprv_strcat(tmp, o.shortName); |
409 | uprv_strcat(tmp, "_"); | |
410 | uprv_strcat(tmp, o.mode); | |
411 | uprv_strcat(tmp, ".mak"); /* MAY NEED TO CHANGE PER PLATFORM */ | |
412 | ||
413 | o.makeFile = uprv_strdup(tmp); | |
414 | ||
415 | out = T_FileStream_open(o.makeFile, "w"); | |
416 | if (out) { | |
417 | pkg_mak_writeHeader(out, &o); /* need to take status */ | |
418 | o.fcn(&o, out, &status); | |
419 | pkg_mak_writeFooter(out, &o); | |
420 | T_FileStream_close(out); | |
421 | } else { | |
422 | fprintf(stderr, "warning: couldn't create %s, will use existing file if any\n", o.makeFile); | |
423 | /*status = U_FILE_ACCESS_ERROR;*/ | |
424 | } | |
425 | ||
426 | if(U_FAILURE(status)) { | |
427 | fprintf(stderr, "Error creating makefile [%s]: %s\n", o.mode, | |
428 | u_errorName(status)); | |
429 | return 1; | |
430 | } | |
431 | ||
432 | if(o.nooutput == TRUE) { | |
433 | return 0; /* nothing to do. */ | |
434 | } | |
435 | ||
436 | return executeMakefile(&o); | |
437 | } | |
438 | ||
439 | /* POSIX - execute makefile */ | |
440 | static int executeMakefile(const UPKGOptions *o) | |
441 | { | |
442 | char cmd[1024]; | |
443 | /*char pwd[1024];*/ | |
444 | const char *make; | |
445 | int rc; | |
446 | ||
447 | make = getenv("MAKE"); | |
448 | ||
449 | if(!make || !make[0]) { | |
450 | make = U_MAKE; | |
451 | } | |
452 | ||
453 | /*getcwd(pwd, 1024);*/ | |
73c04bcf | 454 | #ifdef U_WINDOWS |
b75a7d8f A |
455 | sprintf(cmd, "%s %s%s -f \"%s\" %s %s %s %s", |
456 | make, | |
457 | o->install ? "INSTALLTO=" : "", | |
458 | o->install ? o->install : "", | |
459 | o->makeFile, | |
460 | o->clean ? "clean" : "", | |
461 | o->rebuild ? "rebuild" : "", | |
462 | o->install ? "install" : "", | |
463 | o->makeArgs); | |
73c04bcf A |
464 | #elif defined(OS400) |
465 | sprintf(cmd, "CALL GNU/GMAKE PARM(%s%s%s '-f' '%s' %s %s %s %s%s%s)", | |
b75a7d8f A |
466 | o->install ? "'INSTALLTO=" : "", |
467 | o->install ? o->install : "", | |
468 | o->install ? "'" : "", | |
469 | o->makeFile, | |
470 | o->clean ? "'clean'" : "", | |
471 | o->rebuild ? "'rebuild'" : "", | |
472 | o->install ? "'install'" : "", | |
73c04bcf A |
473 | o->makeArgs && *o->makeArgs ? "'" : "", |
474 | o->makeArgs && *o->makeArgs ? o->makeArgs : "", | |
475 | o->makeArgs && *o->makeArgs ? "'" : ""); | |
b75a7d8f A |
476 | #else |
477 | sprintf(cmd, "%s %s%s -f %s %s %s %s %s", | |
478 | make, | |
479 | o->install ? "INSTALLTO=" : "", | |
480 | o->install ? o->install : "", | |
481 | o->makeFile, | |
482 | o->clean ? "clean" : "", | |
483 | o->rebuild ? "rebuild" : "", | |
484 | o->install ? "install" : "", | |
485 | o->makeArgs); | |
486 | #endif | |
487 | if(o->verbose) { | |
488 | puts(cmd); | |
489 | } | |
490 | ||
491 | rc = system(cmd); | |
492 | ||
493 | if(rc < 0) { | |
494 | fprintf(stderr, "# Failed, rc=%d\n", rc); | |
495 | } | |
496 | ||
497 | return rc < 128 ? rc : (rc >> 8); | |
498 | } | |
499 | ||
500 | ||
501 | static void loadLists(UPKGOptions *o, UErrorCode *status) | |
502 | { | |
503 | CharList *l, *tail = NULL, *tail2 = NULL; | |
504 | FileStream *in; | |
505 | char line[16384]; | |
506 | char *linePtr, *lineNext; | |
507 | const uint32_t lineMax = 16300; | |
374ca955 | 508 | char tmp[1024]; |
b75a7d8f | 509 | char *s; |
374ca955 | 510 | int32_t ln=0; /* line number */ |
b75a7d8f | 511 | |
b75a7d8f A |
512 | for(l = o->fileListFiles; l; l = l->next) { |
513 | if(o->verbose) { | |
514 | fprintf(stdout, "# Reading %s..\n", l->str); | |
515 | } | |
516 | /* TODO: stdin */ | |
374ca955 | 517 | in = T_FileStream_open(l->str, "r"); /* open files list */ |
b75a7d8f A |
518 | |
519 | if(!in) { | |
520 | fprintf(stderr, "Error opening <%s>.\n", l->str); | |
521 | *status = U_FILE_ACCESS_ERROR; | |
522 | return; | |
523 | } | |
374ca955 A |
524 | |
525 | while(T_FileStream_readLine(in, line, sizeof(line))!=NULL) { /* for each line */ | |
73c04bcf A |
526 | ln++; |
527 | if(uprv_strlen(line)>lineMax) { | |
528 | fprintf(stderr, "%s:%d - line too long (over %d chars)\n", l->str, (int)ln, (int)lineMax); | |
529 | exit(1); | |
b75a7d8f | 530 | } |
73c04bcf A |
531 | /* remove spaces at the beginning */ |
532 | linePtr = line; | |
533 | while(isspace(*linePtr)) { | |
534 | linePtr++; | |
b75a7d8f | 535 | } |
73c04bcf A |
536 | s=linePtr; |
537 | /* remove trailing newline characters */ | |
538 | while(*s!=0) { | |
539 | if(*s=='\r' || *s=='\n') { | |
540 | *s=0; | |
541 | break; | |
542 | } | |
b75a7d8f A |
543 | ++s; |
544 | } | |
73c04bcf A |
545 | if((*linePtr == 0) || (*linePtr == '#')) { |
546 | continue; /* comment or empty line */ | |
547 | } | |
548 | ||
549 | /* Now, process the line */ | |
550 | lineNext = NULL; | |
551 | ||
552 | while(linePtr && *linePtr) { /* process space-separated items */ | |
553 | while(*linePtr == ' ') { | |
554 | linePtr++; | |
555 | } | |
556 | /* Find the next quote */ | |
557 | if(linePtr[0] == '"') | |
558 | { | |
559 | lineNext = uprv_strchr(linePtr+1, '"'); | |
560 | if(lineNext == NULL) { | |
561 | fprintf(stderr, "%s:%d - missing trailing double quote (\")\n", | |
562 | l->str, (int)ln); | |
563 | exit(1); | |
564 | } else { | |
565 | lineNext++; | |
566 | if(*lineNext) { | |
567 | if(*lineNext != ' ') { | |
568 | fprintf(stderr, "%s:%d - malformed quoted line at position %d, expected ' ' got '%c'\n", | |
569 | l->str, (int)ln, (int)(lineNext-line), (*lineNext)?*lineNext:'0'); | |
570 | exit(1); | |
571 | } | |
572 | *lineNext = 0; | |
573 | lineNext++; | |
574 | } | |
575 | } | |
b75a7d8f | 576 | } else { |
73c04bcf A |
577 | lineNext = uprv_strchr(linePtr, ' '); |
578 | if(lineNext) { | |
579 | *lineNext = 0; /* terminate at space */ | |
580 | lineNext++; | |
b75a7d8f | 581 | } |
b75a7d8f | 582 | } |
73c04bcf A |
583 | |
584 | /* add the file */ | |
585 | s = (char*)getLongPathname(linePtr); | |
586 | ||
587 | /* normal mode.. o->files is just the bare list without package names */ | |
588 | o->files = pkg_appendToList(o->files, &tail, uprv_strdup(linePtr)); | |
589 | if(uprv_pathIsAbsolute(s)) { | |
590 | 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); | |
591 | exit(U_ILLEGAL_ARGUMENT_ERROR); | |
592 | } | |
374ca955 A |
593 | uprv_strcpy(tmp, o->srcDir); |
594 | uprv_strcat(tmp, o->srcDir[uprv_strlen(o->srcDir)-1]==U_FILE_SEP_CHAR?"":U_FILE_SEP_STRING); | |
374ca955 A |
595 | uprv_strcat(tmp, s); |
596 | o->filePaths = pkg_appendToList(o->filePaths, &tail2, uprv_strdup(tmp)); | |
73c04bcf A |
597 | linePtr = lineNext; |
598 | } /* for each entry on line */ | |
374ca955 | 599 | } /* for each line */ |
b75a7d8f | 600 | T_FileStream_close(in); |
374ca955 | 601 | } /* for each file list file */ |
b75a7d8f A |
602 | } |
603 | ||
604 | /* Try calling icu-config directly to get information */ | |
374ca955 | 605 | static void fillInMakefileFromICUConfig(UOption *option) |
b75a7d8f A |
606 | { |
607 | #if U_HAVE_POPEN | |
374ca955 A |
608 | FILE *p; |
609 | size_t n; | |
610 | static char buf[512] = ""; | |
611 | static const char cmd[] = "icu-config --incfile"; | |
612 | ||
613 | if(options[5].doesOccur) | |
614 | { | |
615 | /* informational */ | |
616 | fprintf(stderr, "%s: No -O option found, trying '%s'.\n", progname, cmd); | |
617 | } | |
618 | ||
619 | p = popen(cmd, "r"); | |
620 | ||
621 | if(p == NULL) | |
622 | { | |
623 | fprintf(stderr, "%s: icu-config: No icu-config found. (fix PATH or use -O option)\n", progname); | |
624 | return; | |
625 | } | |
626 | ||
627 | n = fread(buf, 1, 511, p); | |
628 | ||
629 | pclose(p); | |
630 | ||
631 | if(n<=0) | |
632 | { | |
633 | fprintf(stderr,"%s: icu-config: Could not read from icu-config. (fix PATH or use -O option)\n", progname); | |
634 | return; | |
635 | } | |
636 | ||
637 | if(buf[strlen(buf)-1]=='\n') | |
638 | { | |
639 | buf[strlen(buf)-1]=0; | |
640 | } | |
641 | ||
642 | if(buf[0] == 0) | |
643 | { | |
644 | fprintf(stderr, "%s: icu-config: invalid response from icu-config (fix PATH or use -O option)\n", progname); | |
645 | return; | |
646 | } | |
647 | ||
648 | if(options[5].doesOccur) | |
649 | { | |
650 | /* informational */ | |
651 | fprintf(stderr, "%s: icu-config: using '-O %s'\n", progname, buf); | |
652 | } | |
653 | option->value = buf; | |
654 | option->doesOccur = TRUE; | |
b75a7d8f A |
655 | #else /* ! U_HAVE_POPEN */ |
656 | ||
73c04bcf | 657 | #ifdef U_WINDOWS |
374ca955 A |
658 | char pathbuffer[_MAX_PATH] = {0}; |
659 | char *fullEXEpath = NULL; | |
660 | char *pathstuff = NULL; | |
661 | ||
662 | if (strchr(progname, U_FILE_SEP_CHAR) != NULL || strchr(progname, U_FILE_ALT_SEP_CHAR) != NULL) { | |
663 | /* pkgdata was executed with relative path */ | |
664 | fullEXEpath = _fullpath(pathbuffer, progname, sizeof(pathbuffer)); | |
665 | pathstuff = (char *)options[1].value; | |
666 | ||
667 | if (fullEXEpath) { | |
668 | pathstuff = strrchr(fullEXEpath, U_FILE_SEP_CHAR); | |
669 | if (pathstuff) { | |
670 | pathstuff[1] = 0; | |
671 | uprv_memmove(fullEXEpath + 2, fullEXEpath, uprv_strlen(fullEXEpath)+1); | |
672 | fullEXEpath[0] = PKGDATA_DERIVED_PATH; | |
673 | fullEXEpath[1] = ':'; | |
674 | option->value = uprv_strdup(fullEXEpath); | |
675 | option->doesOccur = TRUE; | |
676 | } | |
677 | } | |
678 | } | |
679 | else { | |
680 | /* pkgdata was executed from the path */ | |
681 | /* Search for file in PATH environment variable: */ | |
682 | _searchenv("pkgdata.exe", "PATH", pathbuffer ); | |
683 | if( *pathbuffer != '\0' ) { | |
684 | fullEXEpath = pathbuffer; | |
685 | pathstuff = strrchr(pathbuffer, U_FILE_SEP_CHAR); | |
686 | if (pathstuff) { | |
687 | pathstuff[1] = 0; | |
688 | uprv_memmove(fullEXEpath + 2, fullEXEpath, uprv_strlen(fullEXEpath)+1); | |
689 | fullEXEpath[0] = PKGDATA_DERIVED_PATH; | |
690 | fullEXEpath[1] = ':'; | |
691 | option->value = uprv_strdup(fullEXEpath); | |
692 | option->doesOccur = TRUE; | |
693 | } | |
694 | } | |
695 | } | |
696 | /* else can't determine the path */ | |
697 | #endif | |
698 | ||
699 | /* no popen available */ | |
700 | /* Put other OS specific ways to search for the Makefile.inc type | |
701 | information or else fail.. */ | |
b75a7d8f A |
702 | |
703 | #endif | |
704 | } |