|  | /* | 
|  | ******************************************************************************* | 
|  | * | 
|  | *   Copyright (C) 1998-2003, International Business Machines | 
|  | *   Corporation and others.  All Rights Reserved. | 
|  | * | 
|  | ******************************************************************************* | 
|  | * | 
|  | * File genrb.c | 
|  | * | 
|  | * Modification History: | 
|  | * | 
|  | *   Date        Name        Description | 
|  | *   05/25/99    stephen     Creation. | 
|  | *   5/10/01     Ram         removed ustdio dependency | 
|  | ******************************************************************************* | 
|  | */ | 
|  |  | 
|  | #include "genrb.h" | 
|  | #include "unicode/uclean.h" | 
|  |  | 
|  | /* Protos */ | 
|  | static void  processFile(const char *filename, const char* cp, const char *inputDir, const char *outputDir, const char *packageName, UErrorCode *status); | 
|  | static char *make_res_filename(const char *filename, const char *outputDir, | 
|  | const char *packageName, UErrorCode *status); | 
|  |  | 
|  | /* File suffixes */ | 
|  | #define RES_SUFFIX ".res" | 
|  | #define COL_SUFFIX ".col" | 
|  |  | 
|  | static char theCurrentFileName[2048]; | 
|  | const char *gCurrentFileName = theCurrentFileName; | 
|  | #ifdef XP_MAC_CONSOLE | 
|  | #include <console.h> | 
|  | #endif | 
|  |  | 
|  | enum | 
|  | { | 
|  | HELP1, | 
|  | HELP2, | 
|  | VERBOSE, | 
|  | QUIET, | 
|  | VERSION, | 
|  | SOURCEDIR, | 
|  | DESTDIR, | 
|  | ENCODING, | 
|  | ICUDATADIR, | 
|  | WRITE_JAVA, | 
|  | COPYRIGHT, | 
|  | PACKAGE_NAME, | 
|  | BUNDLE_NAME, | 
|  | WRITE_XLIFF, | 
|  | TOUCHFILE, | 
|  | STRICT, | 
|  | NO_BINARY_COLLATION, | 
|  | /*added by Jing*/ | 
|  | LANGUAGE | 
|  | }; | 
|  |  | 
|  | UOption options[]={ | 
|  | UOPTION_HELP_H, | 
|  | UOPTION_HELP_QUESTION_MARK, | 
|  | UOPTION_VERBOSE, | 
|  | UOPTION_QUIET, | 
|  | UOPTION_VERSION, | 
|  | UOPTION_SOURCEDIR, | 
|  | UOPTION_DESTDIR, | 
|  | UOPTION_ENCODING, | 
|  | UOPTION_ICUDATADIR, | 
|  | UOPTION_WRITE_JAVA, | 
|  | UOPTION_COPYRIGHT, | 
|  | UOPTION_PACKAGE_NAME, | 
|  | UOPTION_BUNDLE_NAME, | 
|  | UOPTION_DEF( "write-xliff", 'x', UOPT_OPTIONAL_ARG), | 
|  | UOPTION_DEF( "touchfile", 't', UOPT_NO_ARG), | 
|  | UOPTION_DEF( "strict",    'k', UOPT_NO_ARG), /* 14 */ | 
|  | UOPTION_DEF( "noBinaryCollation", 'C', UOPT_NO_ARG),/* 15 */ | 
|  | /*added by Jing*/ | 
|  | UOPTION_DEF( "language",  'l', UOPT_REQUIRES_ARG) | 
|  | }; | 
|  |  | 
|  | static     UBool       write_java = FALSE; | 
|  | static     UBool       write_xliff = FALSE; | 
|  | static     UBool       touchfile = FALSE; | 
|  | static     const char* outputEnc =""; | 
|  | static     const char* gPackageName=NULL; | 
|  | static     const char* bundleName=NULL; | 
|  | /*added by Jing*/ | 
|  | static     const char* language = NULL; | 
|  | static     const char* xliffOutputFileName = NULL; | 
|  | int | 
|  | main(int argc, | 
|  | char* argv[]) | 
|  | { | 
|  | UErrorCode  status    = U_ZERO_ERROR; | 
|  | const char *arg       = NULL; | 
|  | const char *outputDir = NULL; /* NULL = no output directory, use current */ | 
|  | const char *inputDir  = NULL; | 
|  | const char *encoding  = ""; | 
|  | int         i; | 
|  |  | 
|  | U_MAIN_INIT_ARGS(argc, argv); | 
|  |  | 
|  | argc = u_parseArgs(argc, argv, (int32_t)(sizeof(options)/sizeof(options[0])), options); | 
|  |  | 
|  | /* error handling, printing usage message */ | 
|  | if(argc<0) { | 
|  | fprintf(stderr, "%s: error in command line argument \"%s\"\n", argv[0], argv[-argc]); | 
|  | } else if(argc<2) { | 
|  | argc = -1; | 
|  | } | 
|  |  | 
|  | if(options[VERSION].doesOccur) { | 
|  | fprintf(stderr, | 
|  | "%s version %s (ICU version %s).\n" | 
|  | "%s\n", | 
|  | argv[0], GENRB_VERSION, U_ICU_VERSION, U_COPYRIGHT_STRING); | 
|  | return U_ZERO_ERROR; | 
|  | } | 
|  |  | 
|  | if(argc<0 || options[HELP1].doesOccur || options[HELP2].doesOccur) { | 
|  | /* | 
|  | * Broken into chucks because the C89 standard says the minimum | 
|  | * required supported string length is 509 bytes. | 
|  | */ | 
|  | fprintf(stderr, | 
|  | "Usage: %s [OPTIONS] [FILES]\n" | 
|  | "\tReads the list of resource bundle source files and creates\n" | 
|  | "\tbinary version of reosurce bundles (.res files)\n", | 
|  | argv[0]); | 
|  | fprintf(stderr, | 
|  | "Options:\n" | 
|  | "\t-h or -? or --help       this usage text\n" | 
|  | "\t-q or --quiet            do not display warnings\n" | 
|  | "\t-v or --verbose          print extra information when processing files\n" | 
|  | "\t-V or --version          prints out version number and exits\n" | 
|  | "\t-c or --copyright        include copyright notice\n"); | 
|  | fprintf(stderr, | 
|  | "\t-e or --encoding         encoding of source files\n" | 
|  | "\t-d of --destdir          destination directory, followed by the path, defaults to %s\n" | 
|  | "\t-s or --sourcedir        source directory for files followed by path, defaults to %s\n" | 
|  | "\t-i or --icudatadir       directory for locating any needed intermediate data files,\n" | 
|  | "\t                         followed by path, defaults to %s\n", | 
|  | u_getDataDirectory(), u_getDataDirectory(), u_getDataDirectory()); | 
|  | fprintf(stderr, | 
|  | "\t-j or --write-java       write a Java ListResourceBundle for ICU4J, followed by optional encoding\n" | 
|  | "\t                         defaults to ASCII and \\uXXXX format.\n" | 
|  | "\t-p or --package-name     For ICU4J: package name for writing the ListResourceBundle for ICU4J,\n" | 
|  | "\t                         defaults to com.ibm.icu.impl.data\n" | 
|  | "\t                         For ICU4C: Package name for the .res files on output. Specfiying\n" | 
|  | "\t                         'ICUDATA' defaults to the current ICU4C data name.\n"); | 
|  | fprintf(stderr, | 
|  | "\t-b or --bundle-name      bundle name for writing the ListResourceBundle for ICU4J,\n" | 
|  | "\t                         defaults to LocaleElements\n" | 
|  | "\t-x or --write-xliff      write a XLIFF file for the resource bundle. Followed by an optional output file name.\n" | 
|  | "\t-k or --strict           use pedantic parsing of syntax\n" | 
|  | /*added by Jing*/ | 
|  | "\t-l or --language         For XLIFF: language code compliant with ISO 639.\n"); | 
|  |  | 
|  | return argc < 0 ? U_ILLEGAL_ARGUMENT_ERROR : U_ZERO_ERROR; | 
|  | } | 
|  |  | 
|  | if(options[VERBOSE].doesOccur) { | 
|  | setVerbose(TRUE); | 
|  | } | 
|  |  | 
|  | if(options[QUIET].doesOccur) { | 
|  | setShowWarning(FALSE); | 
|  | } | 
|  | if(options[STRICT].doesOccur) { | 
|  | setStrict(TRUE); | 
|  | } | 
|  | if(options[COPYRIGHT].doesOccur){ | 
|  | setIncludeCopyright(TRUE); | 
|  | } | 
|  |  | 
|  | if(options[SOURCEDIR].doesOccur) { | 
|  | inputDir = options[SOURCEDIR].value; | 
|  | } | 
|  |  | 
|  | if(options[DESTDIR].doesOccur) { | 
|  | outputDir = options[DESTDIR].value; | 
|  | } | 
|  | if(options[PACKAGE_NAME].doesOccur) { | 
|  | gPackageName = options[PACKAGE_NAME].value; | 
|  | if(!strcmp(gPackageName, "ICUDATA")) | 
|  | { | 
|  | gPackageName = U_ICUDATA_NAME; | 
|  | } | 
|  | if(gPackageName[0] == 0) | 
|  | { | 
|  | gPackageName = NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | if(options[TOUCHFILE].doesOccur) { | 
|  | if(gPackageName == NULL) { | 
|  | fprintf(stderr, "%s: Don't use touchfile (-t) option with no package.\n", | 
|  | argv[0]); | 
|  | return -1; | 
|  | } | 
|  | touchfile = TRUE; | 
|  | } | 
|  |  | 
|  | if(options[ENCODING].doesOccur) { | 
|  | encoding = options[ENCODING].value; | 
|  | } | 
|  |  | 
|  | if(options[ICUDATADIR].doesOccur) { | 
|  | u_setDataDirectory(options[ICUDATADIR].value); | 
|  | } | 
|  | /* Initialize ICU */ | 
|  | u_init(&status); | 
|  | if (U_FAILURE(status) && status != U_FILE_ACCESS_ERROR) { | 
|  | /* Note: u_init() will try to open ICU property data. | 
|  | *       failures here are expected when building ICU from scratch. | 
|  | *       ignore them. | 
|  | */ | 
|  | fprintf(stderr, "%s: can not initialize ICU.  status = %s\n", | 
|  | argv[0], u_errorName(status)); | 
|  | exit(1); | 
|  | } | 
|  | status = U_ZERO_ERROR; | 
|  | if(options[WRITE_JAVA].doesOccur) { | 
|  | write_java = TRUE; | 
|  | outputEnc = options[WRITE_JAVA].value; | 
|  | } | 
|  |  | 
|  | if(options[BUNDLE_NAME].doesOccur) { | 
|  | bundleName = options[BUNDLE_NAME].value; | 
|  | } | 
|  |  | 
|  | if(options[WRITE_XLIFF].doesOccur) { | 
|  | write_xliff = TRUE; | 
|  | if(options[WRITE_XLIFF].value != NULL){ | 
|  | xliffOutputFileName = options[WRITE_XLIFF].value; | 
|  | } | 
|  | } | 
|  |  | 
|  | if(options[NO_BINARY_COLLATION].doesOccur) { | 
|  | initParser(FALSE); | 
|  | } else { | 
|  | initParser(TRUE); | 
|  | } | 
|  |  | 
|  | /*added by Jing*/ | 
|  | if(options[LANGUAGE].doesOccur) { | 
|  | language = options[LANGUAGE].value; | 
|  | } | 
|  |  | 
|  | /* generate the binary files */ | 
|  | for(i = 1; i < argc; ++i) { | 
|  | status = U_ZERO_ERROR; | 
|  | arg    = getLongPathname(argv[i]); | 
|  |  | 
|  | if (inputDir) { | 
|  | uprv_strcpy(theCurrentFileName, inputDir); | 
|  | uprv_strcat(theCurrentFileName, U_FILE_SEP_STRING); | 
|  | } else { | 
|  | *theCurrentFileName = 0; | 
|  | } | 
|  | uprv_strcat(theCurrentFileName, arg); | 
|  |  | 
|  | if (isVerbose()) { | 
|  | printf("Processing file \"%s\"\n", theCurrentFileName); | 
|  | } | 
|  | processFile(arg, encoding, inputDir, outputDir, gPackageName, &status); | 
|  | } | 
|  |  | 
|  | return status; | 
|  | } | 
|  |  | 
|  | /* Process a file */ | 
|  | static void | 
|  | processFile(const char *filename, const char *cp, const char *inputDir, const char *outputDir, const char *packageName, UErrorCode *status) { | 
|  | /*FileStream     *in           = NULL;*/ | 
|  | struct SRBRoot *data         = NULL; | 
|  | UCHARBUF       *ucbuf        = NULL; | 
|  | char           *rbname       = NULL; | 
|  | char           *openFileName = NULL; | 
|  | char           *inputDirBuf  = NULL; | 
|  |  | 
|  | char           outputFileName[256]; | 
|  |  | 
|  | int32_t dirlen  = 0; | 
|  | int32_t filelen = 0; | 
|  |  | 
|  | if (status==NULL || U_FAILURE(*status)) { | 
|  | return; | 
|  | } | 
|  | if(filename==NULL){ | 
|  | *status=U_ILLEGAL_ARGUMENT_ERROR; | 
|  | return; | 
|  | }else{ | 
|  | filelen = (int32_t)uprv_strlen(filename); | 
|  | } | 
|  | if(inputDir == NULL) { | 
|  | const char *filenameBegin = uprv_strrchr(filename, U_FILE_SEP_CHAR); | 
|  | openFileName = (char *) uprv_malloc(dirlen + filelen + 2); | 
|  | openFileName[0] = '\0'; | 
|  | if (filenameBegin != NULL) { | 
|  | /* | 
|  | * When a filename ../../../data/root.txt is specified, | 
|  | * we presume that the input directory is ../../../data | 
|  | * This is very important when the resource file includes | 
|  | * another file, like UCARules.txt or thaidict.brk. | 
|  | */ | 
|  | int32_t filenameSize = (int32_t)(filenameBegin - filename + 1); | 
|  | inputDirBuf = uprv_strncpy((char *)uprv_malloc(filenameSize), filename, filenameSize); | 
|  |  | 
|  | /* test for NULL */ | 
|  | if(inputDirBuf == NULL) { | 
|  | *status = U_MEMORY_ALLOCATION_ERROR; | 
|  | goto finish; | 
|  | } | 
|  |  | 
|  | inputDirBuf[filenameSize - 1] = 0; | 
|  | inputDir = inputDirBuf; | 
|  | dirlen  = (int32_t)uprv_strlen(inputDir); | 
|  | } | 
|  | }else{ | 
|  | dirlen  = (int32_t)uprv_strlen(inputDir); | 
|  |  | 
|  | if(inputDir[dirlen-1] != U_FILE_SEP_CHAR) { | 
|  | openFileName = (char *) uprv_malloc(dirlen + filelen + 2); | 
|  |  | 
|  | /* test for NULL */ | 
|  | if(openFileName == NULL) { | 
|  | *status = U_MEMORY_ALLOCATION_ERROR; | 
|  | goto finish; | 
|  | } | 
|  |  | 
|  | openFileName[0] = '\0'; | 
|  | /* | 
|  | * append the input dir to openFileName if the first char in | 
|  | * filename is not file seperation char and the last char input directory is  not '.'. | 
|  | * This is to support : | 
|  | * genrb -s. /home/icu/data | 
|  | * genrb -s. icu/data | 
|  | * The user cannot mix notations like | 
|  | * genrb -s. /icu/data --- the absolute path specified. -s redundant | 
|  | * user should use | 
|  | * genrb -s. icu/data  --- start from CWD and look in icu/data dir | 
|  | */ | 
|  | if( (filename[0] != U_FILE_SEP_CHAR) && (inputDir[dirlen-1] !='.')){ | 
|  | uprv_strcpy(openFileName, inputDir); | 
|  | openFileName[dirlen]     = U_FILE_SEP_CHAR; | 
|  | } | 
|  | openFileName[dirlen + 1] = '\0'; | 
|  | } else { | 
|  | openFileName = (char *) uprv_malloc(dirlen + filelen + 1); | 
|  |  | 
|  | /* test for NULL */ | 
|  | if(openFileName == NULL) { | 
|  | *status = U_MEMORY_ALLOCATION_ERROR; | 
|  | goto finish; | 
|  | } | 
|  |  | 
|  | uprv_strcpy(openFileName, inputDir); | 
|  |  | 
|  | } | 
|  | } | 
|  |  | 
|  | uprv_strcat(openFileName, filename); | 
|  |  | 
|  | ucbuf = ucbuf_open(openFileName, &cp,getShowWarning(),TRUE, status); | 
|  |  | 
|  | if(*status == U_FILE_ACCESS_ERROR) { | 
|  |  | 
|  | fprintf(stderr, "couldn't open file %s\n", openFileName == NULL ? filename : openFileName); | 
|  | goto finish; | 
|  | } | 
|  | if (ucbuf == NULL || U_FAILURE(*status)) { | 
|  | fprintf(stderr, "An error occured processing file %s. Error: %s\n", openFileName == NULL ? filename : openFileName,u_errorName(*status)); | 
|  | goto finish; | 
|  | } | 
|  | /* auto detected popular encodings? */ | 
|  | if (cp!=NULL && isVerbose()) { | 
|  | printf("autodetected encoding %s\n", cp); | 
|  | } | 
|  | /* Parse the data into an SRBRoot */ | 
|  | data = parse(ucbuf, inputDir, status); | 
|  |  | 
|  | if (data == NULL || U_FAILURE(*status)) { | 
|  | fprintf(stderr, "couldn't parse the file %s. Error:%s\n", filename,u_errorName(*status)); | 
|  | goto finish; | 
|  | } | 
|  |  | 
|  | /* Determine the target rb filename */ | 
|  | rbname = make_res_filename(filename, outputDir, packageName, status); | 
|  | if(touchfile == TRUE) { | 
|  | FileStream *q; | 
|  | char msg[1024]; | 
|  | char *tfname = NULL; | 
|  |  | 
|  | tfname = make_res_filename(filename, outputDir, NULL, status); | 
|  |  | 
|  | if(U_FAILURE(*status)) | 
|  | { | 
|  | fprintf(stderr, "Error writing touchfile for \"%s\"\n", filename); | 
|  | *status = U_FILE_ACCESS_ERROR; | 
|  | } else { | 
|  | uprv_strcat(tfname, ".res"); | 
|  | sprintf(msg, "This empty file tells nmake that %s in package %s has been updated.\n", | 
|  | filename, packageName); | 
|  |  | 
|  | q = T_FileStream_open(tfname, "w"); | 
|  | if(q == NULL) | 
|  | { | 
|  | fprintf(stderr, "Error writing touchfile \"%s\"\n", tfname); | 
|  | *status = U_FILE_ACCESS_ERROR; | 
|  | } | 
|  | else | 
|  | { | 
|  | T_FileStream_write(q, msg, (int32_t)uprv_strlen(msg)); | 
|  | T_FileStream_close(q); | 
|  | } | 
|  | uprv_free(tfname); | 
|  | } | 
|  |  | 
|  | } | 
|  | if(U_FAILURE(*status)) { | 
|  | fprintf(stderr, "couldn't make the res fileName for  bundle %s. Error:%s\n", filename,u_errorName(*status)); | 
|  | goto finish; | 
|  | } | 
|  | if(write_java== TRUE){ | 
|  | bundle_write_java(data,outputDir,outputEnc, outputFileName, sizeof(outputFileName),packageName,bundleName,status); | 
|  | }else if(write_xliff ==TRUE){ | 
|  | bundle_write_xml(data,outputDir,outputEnc, filename, outputFileName, sizeof(outputFileName),language, xliffOutputFileName,status); | 
|  | }else{ | 
|  | /* Write the data to the file */ | 
|  | bundle_write(data, outputDir, packageName, outputFileName, sizeof(outputFileName), status); | 
|  | } | 
|  | if (U_FAILURE(*status)) { | 
|  | fprintf(stderr, "couldn't write bundle %s. Error:%s\n", outputFileName,u_errorName(*status)); | 
|  | } | 
|  | bundle_close(data, status); | 
|  |  | 
|  | finish: | 
|  |  | 
|  | if (inputDirBuf != NULL) { | 
|  | uprv_free(inputDirBuf); | 
|  | } | 
|  |  | 
|  | if (openFileName != NULL) { | 
|  | uprv_free(openFileName); | 
|  | } | 
|  |  | 
|  | if(ucbuf) { | 
|  | ucbuf_close(ucbuf); | 
|  | } | 
|  |  | 
|  | if (rbname) { | 
|  | uprv_free(rbname); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Generate the target .res file name from the input file name */ | 
|  | static char* | 
|  | make_res_filename(const char *filename, | 
|  | const char *outputDir, | 
|  | const char *packageName, | 
|  | UErrorCode *status) { | 
|  | char *basename; | 
|  | char *dirname; | 
|  | char *resName; | 
|  |  | 
|  | int32_t pkgLen = 0; /* length of package prefix */ | 
|  |  | 
|  | if (U_FAILURE(*status)) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if(packageName != NULL) | 
|  | { | 
|  | pkgLen = (int32_t)(1 + uprv_strlen(packageName)); | 
|  | } | 
|  |  | 
|  | /* setup */ | 
|  | basename = dirname = resName = 0; | 
|  |  | 
|  | /* determine basename, and compiled file names */ | 
|  | basename = (char*) uprv_malloc(sizeof(char) * (uprv_strlen(filename) + 1)); | 
|  | if(basename == 0) { | 
|  | *status = U_MEMORY_ALLOCATION_ERROR; | 
|  | goto finish; | 
|  | } | 
|  |  | 
|  | get_basename(basename, filename); | 
|  |  | 
|  | dirname = (char*) uprv_malloc(sizeof(char) * (uprv_strlen(filename) + 1)); | 
|  | if(dirname == 0) { | 
|  | *status = U_MEMORY_ALLOCATION_ERROR; | 
|  | goto finish; | 
|  | } | 
|  |  | 
|  | get_dirname(dirname, filename); | 
|  |  | 
|  | if (outputDir == NULL) { | 
|  | /* output in same dir as .txt */ | 
|  | resName = (char*) uprv_malloc(sizeof(char) * (uprv_strlen(dirname) | 
|  | + pkgLen | 
|  | + uprv_strlen(basename) | 
|  | + uprv_strlen(RES_SUFFIX) + 8)); | 
|  | if(resName == 0) { | 
|  | *status = U_MEMORY_ALLOCATION_ERROR; | 
|  | goto finish; | 
|  | } | 
|  |  | 
|  | uprv_strcpy(resName, dirname); | 
|  |  | 
|  | if(packageName != NULL) | 
|  | { | 
|  | uprv_strcat(resName, packageName); | 
|  | uprv_strcat(resName, "_"); | 
|  | } | 
|  |  | 
|  | uprv_strcat(resName, basename); | 
|  |  | 
|  | } else { | 
|  | int32_t dirlen      = (int32_t)uprv_strlen(outputDir); | 
|  | int32_t basenamelen = (int32_t)uprv_strlen(basename); | 
|  |  | 
|  | resName = (char*) uprv_malloc(sizeof(char) * (dirlen + pkgLen + basenamelen + 8)); | 
|  |  | 
|  | if (resName == NULL) { | 
|  | *status = U_MEMORY_ALLOCATION_ERROR; | 
|  | goto finish; | 
|  | } | 
|  |  | 
|  | uprv_strcpy(resName, outputDir); | 
|  |  | 
|  | if(outputDir[dirlen] != U_FILE_SEP_CHAR) { | 
|  | resName[dirlen]     = U_FILE_SEP_CHAR; | 
|  | resName[dirlen + 1] = '\0'; | 
|  | } | 
|  |  | 
|  | if(packageName != NULL) | 
|  | { | 
|  | uprv_strcat(resName, packageName); | 
|  | uprv_strcat(resName, "_"); | 
|  | } | 
|  |  | 
|  | uprv_strcat(resName, basename); | 
|  | } | 
|  |  | 
|  | finish: | 
|  | uprv_free(basename); | 
|  | uprv_free(dirname); | 
|  |  | 
|  | return resName; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Local Variables: | 
|  | * indent-tabs-mode: nil | 
|  | * End: | 
|  | */ |