1 /* 2 ******************************************************************************* 3 * 4 * Copyright (C) 1998-2008, 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, This option is deprecated and should not be used ever. */ 51 BUNDLE_NAME, 52 WRITE_XLIFF, 53 STRICT, 54 NO_BINARY_COLLATION, 55 /*added by Jing*/ 56 LANGUAGE, 57 NO_COLLATION_RULES 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, This option is deprecated and should not be used ever. */ 73 UOPTION_BUNDLE_NAME, 74 UOPTION_DEF( "write-xliff", 'x', UOPT_OPTIONAL_ARG), 75 UOPTION_DEF( "strict", 'k', UOPT_NO_ARG), /* 14 */ 76 UOPTION_DEF( "noBinaryCollation", 'C', UOPT_NO_ARG),/* 15 */ 77 UOPTION_DEF( "language", 'l', UOPT_REQUIRES_ARG), /* 16 */ 78 UOPTION_DEF( "omitCollationRules", 'R', UOPT_NO_ARG),/* 17 */ 79 }; 80 81 static UBool write_java = FALSE; 82 static UBool write_xliff = FALSE; 83 static const char* outputEnc =""; 84 static const char* gPackageName=NULL; 85 static const char* bundleName=NULL; 86 /*added by Jing*/ 87 static const char* language = NULL; 88 static const char* xliffOutputFileName = NULL; 89 int 90 main(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; 99 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" 145 "\t defaults to ASCII and \\uXXXX format.\n"); 146 /* This option is deprecated and should not be used ever. 147 "\t-p or --package-name For ICU4J: package name for writing the ListResourceBundle for ICU4J,\n" 148 "\t defaults to com.ibm.icu.impl.data\n"); */ 149 fprintf(stderr, 150 "\t-b or --bundle-name bundle name for writing the ListResourceBundle for ICU4J,\n" 151 "\t defaults to LocaleElements\n" 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" 154 "\t-k or --strict use pedantic parsing of syntax\n" 155 /*added by Jing*/ 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"); 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 } 189 /* This option is deprecated and should never be used. 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 } 200 }*/ 201 202 if(options[ENCODING].doesOccur) { 203 encoding = options[ENCODING].value; 204 } 205 206 if(options[ICUDATADIR].doesOccur) { 207 u_setDataDirectory(options[ICUDATADIR].value); 208 } 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; 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 230 if(options[WRITE_XLIFF].doesOccur) { 231 write_xliff = TRUE; 232 if(options[WRITE_XLIFF].value != NULL){ 233 xliffOutputFileName = options[WRITE_XLIFF].value; 234 } 235 } 236 237 initParser(options[NO_BINARY_COLLATION].doesOccur, options[NO_COLLATION_RULES].doesOccur); 238 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]); 248 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 263 /* Dont return warnings as a failure */ 264 if (! U_FAILURE(status)) { 265 return 0; 266 } 267 268 return status; 269 } 270 271 /* Process a file */ 272 static void 273 processFile(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]; 282 283 int32_t dirlen = 0; 284 int32_t filelen = 0; 285 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 /* 301 * When a filename ../../../data/root.txt is specified, 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 */ 306 int32_t filenameSize = (int32_t)(filenameBegin - filename + 1); 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 /* 333 * append the input dir to openFileName if the first char in 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); 358 359 } 360 } 361 362 uprv_strcat(openFileName, filename); 363 364 ucbuf = ucbuf_open(openFileName, &cp,getShowWarning(),TRUE, status); 365 366 if(*status == U_FILE_ACCESS_ERROR) { 367 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? */ 376 if (cp!=NULL && isVerbose()) { 377 printf("autodetected encoding %s\n", cp); 378 } 379 /* Parse the data into an SRBRoot */ 380 data = parse(ucbuf, inputDir, outputDir, status); 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); 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); 395 }else if(write_xliff ==TRUE){ 396 bundle_write_xml(data,outputDir,outputEnc, filename, outputFileName, sizeof(outputFileName),language, xliffOutputFileName,status); 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 406 finish: 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 */ 426 static char* 427 make_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 { 443 pkgLen = (int32_t)(1 + uprv_strlen(packageName)); 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 514 finish: 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 */ 526