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