]> git.saurik.com Git - apple/icu.git/blame - icuSources/tools/genrb/genrb.c
ICU-400.37.tar.gz
[apple/icu.git] / icuSources / tools / genrb / genrb.c
CommitLineData
b75a7d8f
A
1/*
2*******************************************************************************
3*
46f4442e 4* Copyright (C) 1998-2008, International Business Machines
b75a7d8f
A
5* Corporation and others. All Rights Reserved.
6*
7*******************************************************************************
8*
9* File genrb.c
10*
11* Modification History:
12*
13* Date Name Description
14* 05/25/99 stephen Creation.
15* 5/10/01 Ram removed ustdio dependency
16*******************************************************************************
17*/
18
19#include "genrb.h"
374ca955 20#include "unicode/uclean.h"
b75a7d8f
A
21
22/* Protos */
23static void processFile(const char *filename, const char* cp, const char *inputDir, const char *outputDir, const char *packageName, UErrorCode *status);
374ca955 24static char *make_res_filename(const char *filename, const char *outputDir,
b75a7d8f
A
25 const char *packageName, UErrorCode *status);
26
27/* File suffixes */
28#define RES_SUFFIX ".res"
29#define COL_SUFFIX ".col"
30
374ca955 31static char theCurrentFileName[2048];
b75a7d8f
A
32const char *gCurrentFileName = theCurrentFileName;
33#ifdef XP_MAC_CONSOLE
34#include <console.h>
35#endif
36
37enum
38{
39 HELP1,
40 HELP2,
41 VERBOSE,
42 QUIET,
43 VERSION,
44 SOURCEDIR,
45 DESTDIR,
46 ENCODING,
47 ICUDATADIR,
48 WRITE_JAVA,
49 COPYRIGHT,
46f4442e 50 /* PACKAGE_NAME, This option is deprecated and should not be used ever. */
b75a7d8f 51 BUNDLE_NAME,
374ca955 52 WRITE_XLIFF,
b75a7d8f
A
53 STRICT,
54 NO_BINARY_COLLATION,
55 /*added by Jing*/
46f4442e
A
56 LANGUAGE,
57 NO_COLLATION_RULES
b75a7d8f
A
58};
59
60UOption options[]={
61 UOPTION_HELP_H,
62 UOPTION_HELP_QUESTION_MARK,
63 UOPTION_VERBOSE,
64 UOPTION_QUIET,
65 UOPTION_VERSION,
66 UOPTION_SOURCEDIR,
67 UOPTION_DESTDIR,
68 UOPTION_ENCODING,
69 UOPTION_ICUDATADIR,
70 UOPTION_WRITE_JAVA,
71 UOPTION_COPYRIGHT,
46f4442e 72 /* UOPTION_PACKAGE_NAME, This option is deprecated and should not be used ever. */
b75a7d8f 73 UOPTION_BUNDLE_NAME,
374ca955 74 UOPTION_DEF( "write-xliff", 'x', UOPT_OPTIONAL_ARG),
b75a7d8f
A
75 UOPTION_DEF( "strict", 'k', UOPT_NO_ARG), /* 14 */
76 UOPTION_DEF( "noBinaryCollation", 'C', UOPT_NO_ARG),/* 15 */
46f4442e
A
77 UOPTION_DEF( "language", 'l', UOPT_REQUIRES_ARG), /* 16 */
78 UOPTION_DEF( "omitCollationRules", 'R', UOPT_NO_ARG),/* 17 */
b75a7d8f
A
79 };
80
81static UBool write_java = FALSE;
374ca955 82static UBool write_xliff = FALSE;
b75a7d8f
A
83static const char* outputEnc ="";
84static const char* gPackageName=NULL;
85static const char* bundleName=NULL;
86/*added by Jing*/
87static const char* language = NULL;
374ca955 88static const char* xliffOutputFileName = NULL;
b75a7d8f
A
89int
90main(int argc,
91 char* argv[])
92{
93 UErrorCode status = U_ZERO_ERROR;
94 const char *arg = NULL;
95 const char *outputDir = NULL; /* NULL = no output directory, use current */
96 const char *inputDir = NULL;
97 const char *encoding = "";
98 int i;
374ca955 99
b75a7d8f
A
100 U_MAIN_INIT_ARGS(argc, argv);
101
102 argc = u_parseArgs(argc, argv, (int32_t)(sizeof(options)/sizeof(options[0])), options);
103
104 /* error handling, printing usage message */
105 if(argc<0) {
106 fprintf(stderr, "%s: error in command line argument \"%s\"\n", argv[0], argv[-argc]);
107 } else if(argc<2) {
108 argc = -1;
109 }
110
111 if(options[VERSION].doesOccur) {
112 fprintf(stderr,
113 "%s version %s (ICU version %s).\n"
114 "%s\n",
115 argv[0], GENRB_VERSION, U_ICU_VERSION, U_COPYRIGHT_STRING);
116 return U_ZERO_ERROR;
117 }
118
119 if(argc<0 || options[HELP1].doesOccur || options[HELP2].doesOccur) {
120 /*
121 * Broken into chucks because the C89 standard says the minimum
122 * required supported string length is 509 bytes.
123 */
124 fprintf(stderr,
125 "Usage: %s [OPTIONS] [FILES]\n"
126 "\tReads the list of resource bundle source files and creates\n"
127 "\tbinary version of reosurce bundles (.res files)\n",
128 argv[0]);
129 fprintf(stderr,
130 "Options:\n"
131 "\t-h or -? or --help this usage text\n"
132 "\t-q or --quiet do not display warnings\n"
133 "\t-v or --verbose print extra information when processing files\n"
134 "\t-V or --version prints out version number and exits\n"
135 "\t-c or --copyright include copyright notice\n");
136 fprintf(stderr,
137 "\t-e or --encoding encoding of source files\n"
138 "\t-d of --destdir destination directory, followed by the path, defaults to %s\n"
139 "\t-s or --sourcedir source directory for files followed by path, defaults to %s\n"
140 "\t-i or --icudatadir directory for locating any needed intermediate data files,\n"
141 "\t followed by path, defaults to %s\n",
142 u_getDataDirectory(), u_getDataDirectory(), u_getDataDirectory());
143 fprintf(stderr,
144 "\t-j or --write-java write a Java ListResourceBundle for ICU4J, followed by optional encoding\n"
46f4442e
A
145 "\t defaults to ASCII and \\uXXXX format.\n");
146 /* This option is deprecated and should not be used ever.
b75a7d8f 147 "\t-p or --package-name For ICU4J: package name for writing the ListResourceBundle for ICU4J,\n"
46f4442e 148 "\t defaults to com.ibm.icu.impl.data\n"); */
b75a7d8f
A
149 fprintf(stderr,
150 "\t-b or --bundle-name bundle name for writing the ListResourceBundle for ICU4J,\n"
151 "\t defaults to LocaleElements\n"
46f4442e
A
152 "\t-x or --write-xliff write an XLIFF file for the resource bundle. Followed by\n"
153 "\t an optional output file name.\n"
b75a7d8f
A
154 "\t-k or --strict use pedantic parsing of syntax\n"
155 /*added by Jing*/
46f4442e
A
156 "\t-l or --language for XLIFF: language code compliant with BCP 47.\n");
157 fprintf(stderr,
158 "\t-C or --noBinaryCollation do not generate binary collation image;\n"
159 "\t makes .res file smaller but collator instantiation much slower;\n"
160 "\t maintains ability to get tailoring rules\n"
161 "\t-R or --omitCollationRules do not include collation (tailoring) rules;\n"
162 "\t makes .res file smaller and maintains collator instantiation speed\n"
163 "\t but tailoring rules will not be available (they are rarely used)\n");
b75a7d8f
A
164
165 return argc < 0 ? U_ILLEGAL_ARGUMENT_ERROR : U_ZERO_ERROR;
166 }
167
168 if(options[VERBOSE].doesOccur) {
169 setVerbose(TRUE);
170 }
171
172 if(options[QUIET].doesOccur) {
173 setShowWarning(FALSE);
174 }
175 if(options[STRICT].doesOccur) {
176 setStrict(TRUE);
177 }
178 if(options[COPYRIGHT].doesOccur){
179 setIncludeCopyright(TRUE);
180 }
181
182 if(options[SOURCEDIR].doesOccur) {
183 inputDir = options[SOURCEDIR].value;
184 }
185
186 if(options[DESTDIR].doesOccur) {
187 outputDir = options[DESTDIR].value;
188 }
46f4442e 189 /* This option is deprecated and should never be used.
b75a7d8f
A
190 if(options[PACKAGE_NAME].doesOccur) {
191 gPackageName = options[PACKAGE_NAME].value;
192 if(!strcmp(gPackageName, "ICUDATA"))
193 {
194 gPackageName = U_ICUDATA_NAME;
195 }
196 if(gPackageName[0] == 0)
197 {
198 gPackageName = NULL;
199 }
46f4442e 200 }*/
b75a7d8f 201
b75a7d8f
A
202 if(options[ENCODING].doesOccur) {
203 encoding = options[ENCODING].value;
204 }
205
206 if(options[ICUDATADIR].doesOccur) {
207 u_setDataDirectory(options[ICUDATADIR].value);
208 }
374ca955
A
209 /* Initialize ICU */
210 u_init(&status);
211 if (U_FAILURE(status) && status != U_FILE_ACCESS_ERROR) {
212 /* Note: u_init() will try to open ICU property data.
213 * failures here are expected when building ICU from scratch.
214 * ignore them.
215 */
216 fprintf(stderr, "%s: can not initialize ICU. status = %s\n",
217 argv[0], u_errorName(status));
218 exit(1);
219 }
220 status = U_ZERO_ERROR;
b75a7d8f
A
221 if(options[WRITE_JAVA].doesOccur) {
222 write_java = TRUE;
223 outputEnc = options[WRITE_JAVA].value;
224 }
225
226 if(options[BUNDLE_NAME].doesOccur) {
227 bundleName = options[BUNDLE_NAME].value;
228 }
229
374ca955
A
230 if(options[WRITE_XLIFF].doesOccur) {
231 write_xliff = TRUE;
232 if(options[WRITE_XLIFF].value != NULL){
233 xliffOutputFileName = options[WRITE_XLIFF].value;
234 }
b75a7d8f
A
235 }
236
46f4442e 237 initParser(options[NO_BINARY_COLLATION].doesOccur, options[NO_COLLATION_RULES].doesOccur);
374ca955 238
b75a7d8f
A
239 /*added by Jing*/
240 if(options[LANGUAGE].doesOccur) {
241 language = options[LANGUAGE].value;
242 }
243
244 /* generate the binary files */
245 for(i = 1; i < argc; ++i) {
246 status = U_ZERO_ERROR;
247 arg = getLongPathname(argv[i]);
374ca955 248
b75a7d8f
A
249 if (inputDir) {
250 uprv_strcpy(theCurrentFileName, inputDir);
251 uprv_strcat(theCurrentFileName, U_FILE_SEP_STRING);
252 } else {
253 *theCurrentFileName = 0;
254 }
255 uprv_strcat(theCurrentFileName, arg);
256
257 if (isVerbose()) {
258 printf("Processing file \"%s\"\n", theCurrentFileName);
259 }
260 processFile(arg, encoding, inputDir, outputDir, gPackageName, &status);
261 }
262
46f4442e
A
263 /* Dont return warnings as a failure */
264 if (! U_FAILURE(status)) {
265 return 0;
266 }
267
b75a7d8f
A
268 return status;
269}
270
271/* Process a file */
272static void
273processFile(const char *filename, const char *cp, const char *inputDir, const char *outputDir, const char *packageName, UErrorCode *status) {
274 /*FileStream *in = NULL;*/
275 struct SRBRoot *data = NULL;
276 UCHARBUF *ucbuf = NULL;
277 char *rbname = NULL;
278 char *openFileName = NULL;
279 char *inputDirBuf = NULL;
280
281 char outputFileName[256];
374ca955 282
b75a7d8f
A
283 int32_t dirlen = 0;
284 int32_t filelen = 0;
374ca955 285
b75a7d8f
A
286 if (status==NULL || U_FAILURE(*status)) {
287 return;
288 }
289 if(filename==NULL){
290 *status=U_ILLEGAL_ARGUMENT_ERROR;
291 return;
292 }else{
293 filelen = (int32_t)uprv_strlen(filename);
294 }
295 if(inputDir == NULL) {
296 const char *filenameBegin = uprv_strrchr(filename, U_FILE_SEP_CHAR);
297 openFileName = (char *) uprv_malloc(dirlen + filelen + 2);
298 openFileName[0] = '\0';
299 if (filenameBegin != NULL) {
300 /*
374ca955 301 * When a filename ../../../data/root.txt is specified,
b75a7d8f
A
302 * we presume that the input directory is ../../../data
303 * This is very important when the resource file includes
304 * another file, like UCARules.txt or thaidict.brk.
305 */
374ca955 306 int32_t filenameSize = (int32_t)(filenameBegin - filename + 1);
b75a7d8f
A
307 inputDirBuf = uprv_strncpy((char *)uprv_malloc(filenameSize), filename, filenameSize);
308
309 /* test for NULL */
310 if(inputDirBuf == NULL) {
311 *status = U_MEMORY_ALLOCATION_ERROR;
312 goto finish;
313 }
314
315 inputDirBuf[filenameSize - 1] = 0;
316 inputDir = inputDirBuf;
317 dirlen = (int32_t)uprv_strlen(inputDir);
318 }
319 }else{
320 dirlen = (int32_t)uprv_strlen(inputDir);
321
322 if(inputDir[dirlen-1] != U_FILE_SEP_CHAR) {
323 openFileName = (char *) uprv_malloc(dirlen + filelen + 2);
324
325 /* test for NULL */
326 if(openFileName == NULL) {
327 *status = U_MEMORY_ALLOCATION_ERROR;
328 goto finish;
329 }
330
331 openFileName[0] = '\0';
332 /*
374ca955 333 * append the input dir to openFileName if the first char in
b75a7d8f
A
334 * filename is not file seperation char and the last char input directory is not '.'.
335 * This is to support :
336 * genrb -s. /home/icu/data
337 * genrb -s. icu/data
338 * The user cannot mix notations like
339 * genrb -s. /icu/data --- the absolute path specified. -s redundant
340 * user should use
341 * genrb -s. icu/data --- start from CWD and look in icu/data dir
342 */
343 if( (filename[0] != U_FILE_SEP_CHAR) && (inputDir[dirlen-1] !='.')){
344 uprv_strcpy(openFileName, inputDir);
345 openFileName[dirlen] = U_FILE_SEP_CHAR;
346 }
347 openFileName[dirlen + 1] = '\0';
348 } else {
349 openFileName = (char *) uprv_malloc(dirlen + filelen + 1);
350
351 /* test for NULL */
352 if(openFileName == NULL) {
353 *status = U_MEMORY_ALLOCATION_ERROR;
354 goto finish;
355 }
356
357 uprv_strcpy(openFileName, inputDir);
374ca955 358
b75a7d8f
A
359 }
360 }
361
362 uprv_strcat(openFileName, filename);
363
364 ucbuf = ucbuf_open(openFileName, &cp,getShowWarning(),TRUE, status);
374ca955 365
b75a7d8f 366 if(*status == U_FILE_ACCESS_ERROR) {
374ca955 367
b75a7d8f
A
368 fprintf(stderr, "couldn't open file %s\n", openFileName == NULL ? filename : openFileName);
369 goto finish;
370 }
371 if (ucbuf == NULL || U_FAILURE(*status)) {
372 fprintf(stderr, "An error occured processing file %s. Error: %s\n", openFileName == NULL ? filename : openFileName,u_errorName(*status));
373 goto finish;
374 }
375 /* auto detected popular encodings? */
374ca955 376 if (cp!=NULL && isVerbose()) {
b75a7d8f
A
377 printf("autodetected encoding %s\n", cp);
378 }
379 /* Parse the data into an SRBRoot */
73c04bcf 380 data = parse(ucbuf, inputDir, outputDir, status);
b75a7d8f
A
381
382 if (data == NULL || U_FAILURE(*status)) {
383 fprintf(stderr, "couldn't parse the file %s. Error:%s\n", filename,u_errorName(*status));
384 goto finish;
385 }
386
387 /* Determine the target rb filename */
388 rbname = make_res_filename(filename, outputDir, packageName, status);
b75a7d8f
A
389 if(U_FAILURE(*status)) {
390 fprintf(stderr, "couldn't make the res fileName for bundle %s. Error:%s\n", filename,u_errorName(*status));
391 goto finish;
392 }
393 if(write_java== TRUE){
394 bundle_write_java(data,outputDir,outputEnc, outputFileName, sizeof(outputFileName),packageName,bundleName,status);
374ca955
A
395 }else if(write_xliff ==TRUE){
396 bundle_write_xml(data,outputDir,outputEnc, filename, outputFileName, sizeof(outputFileName),language, xliffOutputFileName,status);
b75a7d8f
A
397 }else{
398 /* Write the data to the file */
399 bundle_write(data, outputDir, packageName, outputFileName, sizeof(outputFileName), status);
400 }
401 if (U_FAILURE(*status)) {
402 fprintf(stderr, "couldn't write bundle %s. Error:%s\n", outputFileName,u_errorName(*status));
403 }
404 bundle_close(data, status);
405
406finish:
407
408 if (inputDirBuf != NULL) {
409 uprv_free(inputDirBuf);
410 }
411
412 if (openFileName != NULL) {
413 uprv_free(openFileName);
414 }
415
416 if(ucbuf) {
417 ucbuf_close(ucbuf);
418 }
419
420 if (rbname) {
421 uprv_free(rbname);
422 }
423}
424
425/* Generate the target .res file name from the input file name */
426static char*
427make_res_filename(const char *filename,
428 const char *outputDir,
429 const char *packageName,
430 UErrorCode *status) {
431 char *basename;
432 char *dirname;
433 char *resName;
434
435 int32_t pkgLen = 0; /* length of package prefix */
436
437 if (U_FAILURE(*status)) {
438 return 0;
439 }
440
441 if(packageName != NULL)
442 {
374ca955 443 pkgLen = (int32_t)(1 + uprv_strlen(packageName));
b75a7d8f
A
444 }
445
446 /* setup */
447 basename = dirname = resName = 0;
448
449 /* determine basename, and compiled file names */
450 basename = (char*) uprv_malloc(sizeof(char) * (uprv_strlen(filename) + 1));
451 if(basename == 0) {
452 *status = U_MEMORY_ALLOCATION_ERROR;
453 goto finish;
454 }
455
456 get_basename(basename, filename);
457
458 dirname = (char*) uprv_malloc(sizeof(char) * (uprv_strlen(filename) + 1));
459 if(dirname == 0) {
460 *status = U_MEMORY_ALLOCATION_ERROR;
461 goto finish;
462 }
463
464 get_dirname(dirname, filename);
465
466 if (outputDir == NULL) {
467 /* output in same dir as .txt */
468 resName = (char*) uprv_malloc(sizeof(char) * (uprv_strlen(dirname)
469 + pkgLen
470 + uprv_strlen(basename)
471 + uprv_strlen(RES_SUFFIX) + 8));
472 if(resName == 0) {
473 *status = U_MEMORY_ALLOCATION_ERROR;
474 goto finish;
475 }
476
477 uprv_strcpy(resName, dirname);
478
479 if(packageName != NULL)
480 {
481 uprv_strcat(resName, packageName);
482 uprv_strcat(resName, "_");
483 }
484
485 uprv_strcat(resName, basename);
486
487 } else {
488 int32_t dirlen = (int32_t)uprv_strlen(outputDir);
489 int32_t basenamelen = (int32_t)uprv_strlen(basename);
490
491 resName = (char*) uprv_malloc(sizeof(char) * (dirlen + pkgLen + basenamelen + 8));
492
493 if (resName == NULL) {
494 *status = U_MEMORY_ALLOCATION_ERROR;
495 goto finish;
496 }
497
498 uprv_strcpy(resName, outputDir);
499
500 if(outputDir[dirlen] != U_FILE_SEP_CHAR) {
501 resName[dirlen] = U_FILE_SEP_CHAR;
502 resName[dirlen + 1] = '\0';
503 }
504
505 if(packageName != NULL)
506 {
507 uprv_strcat(resName, packageName);
508 uprv_strcat(resName, "_");
509 }
510
511 uprv_strcat(resName, basename);
512 }
513
514finish:
515 uprv_free(basename);
516 uprv_free(dirname);
517
518 return resName;
519}
520
521/*
522 * Local Variables:
523 * indent-tabs-mode: nil
524 * End:
525 */