Home | History | Annotate | Download | only in genrb
      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