Index: icu46/source/tools/genrb/parse.c |
=================================================================== |
--- icu46/source/tools/genrb/parse.c (revision 0) |
+++ icu46/source/tools/genrb/parse.c (revision 0) |
@@ -0,0 +1,2131 @@ |
+/* |
+******************************************************************************* |
+* |
+* Copyright (C) 1998-2010, International Business Machines |
+* Corporation and others. All Rights Reserved. |
+* |
+******************************************************************************* |
+* |
+* File parse.c |
+* |
+* Modification History: |
+* |
+* Date Name Description |
+* 05/26/99 stephen Creation. |
+* 02/25/00 weiv Overhaul to write udata |
+* 5/10/01 Ram removed ustdio dependency |
+* 06/10/2001 Dominic Ludlam <dom@recoil.org> Rewritten |
+******************************************************************************* |
+*/ |
+ |
+#include "ucol_imp.h" |
+#include "parse.h" |
+#include "errmsg.h" |
+#include "uhash.h" |
+#include "cmemory.h" |
+#include "cstring.h" |
+#include "uinvchar.h" |
+#include "read.h" |
+#include "ustr.h" |
+#include "reslist.h" |
+#include "rbt_pars.h" |
+#include "genrb.h" |
+#include "unicode/ustring.h" |
+#include "unicode/uscript.h" |
+#include "unicode/putil.h" |
+#include <stdio.h> |
+ |
+extern UBool gIncludeUnihanColl; |
+ |
+/* Number of tokens to read ahead of the current stream position */ |
+#define MAX_LOOKAHEAD 3 |
+ |
+#define CR 0x000D |
+#define LF 0x000A |
+#define SPACE 0x0020 |
+#define TAB 0x0009 |
+#define ESCAPE 0x005C |
+#define HASH 0x0023 |
+#define QUOTE 0x0027 |
+#define ZERO 0x0030 |
+#define STARTCOMMAND 0x005B |
+#define ENDCOMMAND 0x005D |
+#define OPENSQBRACKET 0x005B |
+#define CLOSESQBRACKET 0x005D |
+ |
+struct Lookahead |
+{ |
+ enum ETokenType type; |
+ struct UString value; |
+ struct UString comment; |
+ uint32_t line; |
+}; |
+ |
+/* keep in sync with token defines in read.h */ |
+const char *tokenNames[TOK_TOKEN_COUNT] = |
+{ |
+ "string", /* A string token, such as "MonthNames" */ |
+ "'{'", /* An opening brace character */ |
+ "'}'", /* A closing brace character */ |
+ "','", /* A comma */ |
+ "':'", /* A colon */ |
+ |
+ "<end of file>", /* End of the file has been reached successfully */ |
+ "<end of line>" |
+}; |
+ |
+/* Just to store "TRUE" */ |
+static const UChar trueValue[] = {0x0054, 0x0052, 0x0055, 0x0045, 0x0000}; |
+ |
+typedef struct { |
+ struct Lookahead lookahead[MAX_LOOKAHEAD + 1]; |
+ uint32_t lookaheadPosition; |
+ UCHARBUF *buffer; |
+ struct SRBRoot *bundle; |
+ const char *inputdir; |
+ uint32_t inputdirLength; |
+ const char *outputdir; |
+ uint32_t outputdirLength; |
+} ParseState; |
+ |
+static UBool gMakeBinaryCollation = TRUE; |
+static UBool gOmitCollationRules = FALSE; |
+ |
+typedef struct SResource * |
+ParseResourceFunction(ParseState* state, char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status); |
+ |
+static struct SResource *parseResource(ParseState* state, char *tag, const struct UString *comment, UErrorCode *status); |
+ |
+/* The nature of the lookahead buffer: |
+ There are MAX_LOOKAHEAD + 1 slots, used as a circular buffer. This provides |
+ MAX_LOOKAHEAD lookahead tokens and a slot for the current token and value. |
+ When getToken is called, the current pointer is moved to the next slot and the |
+ old slot is filled with the next token from the reader by calling getNextToken. |
+ The token values are stored in the slot, which means that token values don't |
+ survive a call to getToken, ie. |
+ |
+ UString *value; |
+ |
+ getToken(&value, NULL, status); |
+ getToken(NULL, NULL, status); bad - value is now a different string |
+*/ |
+static void |
+initLookahead(ParseState* state, UCHARBUF *buf, UErrorCode *status) |
+{ |
+ static uint32_t initTypeStrings = 0; |
+ uint32_t i; |
+ |
+ if (!initTypeStrings) |
+ { |
+ initTypeStrings = 1; |
+ } |
+ |
+ state->lookaheadPosition = 0; |
+ state->buffer = buf; |
+ |
+ resetLineNumber(); |
+ |
+ for (i = 0; i < MAX_LOOKAHEAD; i++) |
+ { |
+ state->lookahead[i].type = getNextToken(state->buffer, &state->lookahead[i].value, &state->lookahead[i].line, &state->lookahead[i].comment, status); |
+ if (U_FAILURE(*status)) |
+ { |
+ return; |
+ } |
+ } |
+ |
+ *status = U_ZERO_ERROR; |
+} |
+ |
+static void |
+cleanupLookahead(ParseState* state) |
+{ |
+ uint32_t i; |
+ for (i = 0; i < MAX_LOOKAHEAD; i++) |
+ { |
+ ustr_deinit(&state->lookahead[i].value); |
+ ustr_deinit(&state->lookahead[i].comment); |
+ } |
+ |
+} |
+ |
+static enum ETokenType |
+getToken(ParseState* state, struct UString **tokenValue, struct UString* comment, uint32_t *linenumber, UErrorCode *status) |
+{ |
+ enum ETokenType result; |
+ uint32_t i; |
+ |
+ result = state->lookahead[state->lookaheadPosition].type; |
+ |
+ if (tokenValue != NULL) |
+ { |
+ *tokenValue = &state->lookahead[state->lookaheadPosition].value; |
+ } |
+ |
+ if (linenumber != NULL) |
+ { |
+ *linenumber = state->lookahead[state->lookaheadPosition].line; |
+ } |
+ |
+ if (comment != NULL) |
+ { |
+ ustr_cpy(comment, &(state->lookahead[state->lookaheadPosition].comment), status); |
+ } |
+ |
+ i = (state->lookaheadPosition + MAX_LOOKAHEAD) % (MAX_LOOKAHEAD + 1); |
+ state->lookaheadPosition = (state->lookaheadPosition + 1) % (MAX_LOOKAHEAD + 1); |
+ ustr_setlen(&state->lookahead[i].comment, 0, status); |
+ ustr_setlen(&state->lookahead[i].value, 0, status); |
+ state->lookahead[i].type = getNextToken(state->buffer, &state->lookahead[i].value, &state->lookahead[i].line, &state->lookahead[i].comment, status); |
+ |
+ /* printf("getToken, returning %s\n", tokenNames[result]); */ |
+ |
+ return result; |
+} |
+ |
+static enum ETokenType |
+peekToken(ParseState* state, uint32_t lookaheadCount, struct UString **tokenValue, uint32_t *linenumber, struct UString *comment, UErrorCode *status) |
+{ |
+ uint32_t i = (state->lookaheadPosition + lookaheadCount) % (MAX_LOOKAHEAD + 1); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ return TOK_ERROR; |
+ } |
+ |
+ if (lookaheadCount >= MAX_LOOKAHEAD) |
+ { |
+ *status = U_INTERNAL_PROGRAM_ERROR; |
+ return TOK_ERROR; |
+ } |
+ |
+ if (tokenValue != NULL) |
+ { |
+ *tokenValue = &state->lookahead[i].value; |
+ } |
+ |
+ if (linenumber != NULL) |
+ { |
+ *linenumber = state->lookahead[i].line; |
+ } |
+ |
+ if(comment != NULL){ |
+ ustr_cpy(comment, &(state->lookahead[state->lookaheadPosition].comment), status); |
+ } |
+ |
+ return state->lookahead[i].type; |
+} |
+ |
+static void |
+expect(ParseState* state, enum ETokenType expectedToken, struct UString **tokenValue, struct UString *comment, uint32_t *linenumber, UErrorCode *status) |
+{ |
+ uint32_t line; |
+ |
+ enum ETokenType token = getToken(state, tokenValue, comment, &line, status); |
+ |
+ if (linenumber != NULL) |
+ { |
+ *linenumber = line; |
+ } |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ return; |
+ } |
+ |
+ if (token != expectedToken) |
+ { |
+ *status = U_INVALID_FORMAT_ERROR; |
+ error(line, "expecting %s, got %s", tokenNames[expectedToken], tokenNames[token]); |
+ } |
+ else |
+ { |
+ *status = U_ZERO_ERROR; |
+ } |
+} |
+ |
+static char *getInvariantString(ParseState* state, uint32_t *line, struct UString *comment, UErrorCode *status) |
+{ |
+ struct UString *tokenValue; |
+ char *result; |
+ uint32_t count; |
+ |
+ expect(state, TOK_STRING, &tokenValue, comment, line, status); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ return NULL; |
+ } |
+ |
+ count = u_strlen(tokenValue->fChars); |
+ if(!uprv_isInvariantUString(tokenValue->fChars, count)) { |
+ *status = U_INVALID_FORMAT_ERROR; |
+ error(*line, "invariant characters required for table keys, binary data, etc."); |
+ return NULL; |
+ } |
+ |
+ result = uprv_malloc(count+1); |
+ |
+ if (result == NULL) |
+ { |
+ *status = U_MEMORY_ALLOCATION_ERROR; |
+ return NULL; |
+ } |
+ |
+ u_UCharsToChars(tokenValue->fChars, result, count+1); |
+ return result; |
+} |
+ |
+static struct SResource * |
+parseUCARules(ParseState* state, char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status) |
+{ |
+ struct SResource *result = NULL; |
+ struct UString *tokenValue; |
+ FileStream *file = NULL; |
+ char filename[256] = { '\0' }; |
+ char cs[128] = { '\0' }; |
+ uint32_t line; |
+ int len=0; |
+ UBool quoted = FALSE; |
+ UCHARBUF *ucbuf=NULL; |
+ UChar32 c = 0; |
+ const char* cp = NULL; |
+ UChar *pTarget = NULL; |
+ UChar *target = NULL; |
+ UChar *targetLimit = NULL; |
+ int32_t size = 0; |
+ |
+ expect(state, TOK_STRING, &tokenValue, NULL, &line, status); |
+ |
+ if(isVerbose()){ |
+ printf(" %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline); |
+ } |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ return NULL; |
+ } |
+ /* make the filename including the directory */ |
+ if (state->inputdir != NULL) |
+ { |
+ uprv_strcat(filename, state->inputdir); |
+ |
+ if (state->inputdir[state->inputdirLength - 1] != U_FILE_SEP_CHAR) |
+ { |
+ uprv_strcat(filename, U_FILE_SEP_STRING); |
+ } |
+ } |
+ |
+ u_UCharsToChars(tokenValue->fChars, cs, tokenValue->fLength); |
+ |
+ expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ return NULL; |
+ } |
+ uprv_strcat(filename, cs); |
+ |
+ if(gOmitCollationRules) { |
+ return res_none(); |
+ } |
+ |
+ ucbuf = ucbuf_open(filename, &cp, getShowWarning(),FALSE, status); |
+ |
+ if (U_FAILURE(*status)) { |
+ error(line, "An error occured while opening the input file %s\n", filename); |
+ return NULL; |
+ } |
+ |
+ /* We allocate more space than actually required |
+ * since the actual size needed for storing UChars |
+ * is not known in UTF-8 byte stream |
+ */ |
+ size = ucbuf_size(ucbuf) + 1; |
+ pTarget = (UChar*) uprv_malloc(U_SIZEOF_UCHAR * size); |
+ uprv_memset(pTarget, 0, size*U_SIZEOF_UCHAR); |
+ target = pTarget; |
+ targetLimit = pTarget+size; |
+ |
+ /* read the rules into the buffer */ |
+ while (target < targetLimit) |
+ { |
+ c = ucbuf_getc(ucbuf, status); |
+ if(c == QUOTE) { |
+ quoted = (UBool)!quoted; |
+ } |
+ /* weiv (06/26/2002): adding the following: |
+ * - preserving spaces in commands [...] |
+ * - # comments until the end of line |
+ */ |
+ if (c == STARTCOMMAND && !quoted) |
+ { |
+ /* preserve commands |
+ * closing bracket will be handled by the |
+ * append at the end of the loop |
+ */ |
+ while(c != ENDCOMMAND) { |
+ U_APPEND_CHAR32(c, target,len); |
+ c = ucbuf_getc(ucbuf, status); |
+ } |
+ } |
+ else if (c == HASH && !quoted) { |
+ /* skip comments */ |
+ while(c != CR && c != LF) { |
+ c = ucbuf_getc(ucbuf, status); |
+ } |
+ continue; |
+ } |
+ else if (c == ESCAPE) |
+ { |
+ c = unescape(ucbuf, status); |
+ |
+ if (c == U_ERR) |
+ { |
+ uprv_free(pTarget); |
+ T_FileStream_close(file); |
+ return NULL; |
+ } |
+ } |
+ else if (!quoted && (c == SPACE || c == TAB || c == CR || c == LF)) |
+ { |
+ /* ignore spaces carriage returns |
+ * and line feed unless in the form \uXXXX |
+ */ |
+ continue; |
+ } |
+ |
+ /* Append UChar * after dissembling if c > 0xffff*/ |
+ if (c != U_EOF) |
+ { |
+ U_APPEND_CHAR32(c, target,len); |
+ } |
+ else |
+ { |
+ break; |
+ } |
+ } |
+ |
+ /* terminate the string */ |
+ if(target < targetLimit){ |
+ *target = 0x0000; |
+ } |
+ |
+ result = string_open(state->bundle, tag, pTarget, (int32_t)(target - pTarget), NULL, status); |
+ |
+ |
+ ucbuf_close(ucbuf); |
+ uprv_free(pTarget); |
+ T_FileStream_close(file); |
+ |
+ return result; |
+} |
+ |
+static struct SResource * |
+parseTransliterator(ParseState* state, char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status) |
+{ |
+ struct SResource *result = NULL; |
+ struct UString *tokenValue; |
+ FileStream *file = NULL; |
+ char filename[256] = { '\0' }; |
+ char cs[128] = { '\0' }; |
+ uint32_t line; |
+ UCHARBUF *ucbuf=NULL; |
+ const char* cp = NULL; |
+ UChar *pTarget = NULL; |
+ const UChar *pSource = NULL; |
+ int32_t size = 0; |
+ |
+ expect(state, TOK_STRING, &tokenValue, NULL, &line, status); |
+ |
+ if(isVerbose()){ |
+ printf(" %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline); |
+ } |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ return NULL; |
+ } |
+ /* make the filename including the directory */ |
+ if (state->inputdir != NULL) |
+ { |
+ uprv_strcat(filename, state->inputdir); |
+ |
+ if (state->inputdir[state->inputdirLength - 1] != U_FILE_SEP_CHAR) |
+ { |
+ uprv_strcat(filename, U_FILE_SEP_STRING); |
+ } |
+ } |
+ |
+ u_UCharsToChars(tokenValue->fChars, cs, tokenValue->fLength); |
+ |
+ expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ return NULL; |
+ } |
+ uprv_strcat(filename, cs); |
+ |
+ |
+ ucbuf = ucbuf_open(filename, &cp, getShowWarning(),FALSE, status); |
+ |
+ if (U_FAILURE(*status)) { |
+ error(line, "An error occured while opening the input file %s\n", filename); |
+ return NULL; |
+ } |
+ |
+ /* We allocate more space than actually required |
+ * since the actual size needed for storing UChars |
+ * is not known in UTF-8 byte stream |
+ */ |
+ pSource = ucbuf_getBuffer(ucbuf, &size, status); |
+ pTarget = (UChar*) uprv_malloc(U_SIZEOF_UCHAR * (size + 1)); |
+ uprv_memset(pTarget, 0, size*U_SIZEOF_UCHAR); |
+ |
+#if !UCONFIG_NO_TRANSLITERATION |
+ size = utrans_stripRules(pSource, size, pTarget, status); |
+#else |
+ size = 0; |
+ fprintf(stderr, " Warning: writing empty transliteration data ( UCONFIG_NO_TRANSLITERATION ) \n"); |
+#endif |
+ result = string_open(state->bundle, tag, pTarget, size, NULL, status); |
+ |
+ ucbuf_close(ucbuf); |
+ uprv_free(pTarget); |
+ T_FileStream_close(file); |
+ |
+ return result; |
+} |
+static struct SResource* dependencyArray = NULL; |
+ |
+static struct SResource * |
+parseDependency(ParseState* state, char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status) |
+{ |
+ struct SResource *result = NULL; |
+ struct SResource *elem = NULL; |
+ struct UString *tokenValue; |
+ uint32_t line; |
+ char filename[256] = { '\0' }; |
+ char cs[128] = { '\0' }; |
+ |
+ expect(state, TOK_STRING, &tokenValue, NULL, &line, status); |
+ |
+ if(isVerbose()){ |
+ printf(" %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline); |
+ } |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ return NULL; |
+ } |
+ /* make the filename including the directory */ |
+ if (state->outputdir != NULL) |
+ { |
+ uprv_strcat(filename, state->outputdir); |
+ |
+ if (state->outputdir[state->outputdirLength - 1] != U_FILE_SEP_CHAR) |
+ { |
+ uprv_strcat(filename, U_FILE_SEP_STRING); |
+ } |
+ } |
+ |
+ u_UCharsToChars(tokenValue->fChars, cs, tokenValue->fLength); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ return NULL; |
+ } |
+ uprv_strcat(filename, cs); |
+ if(!T_FileStream_file_exists(filename)){ |
+ if(isStrict()){ |
+ error(line, "The dependency file %s does not exist. Please make sure it exists.\n",filename); |
+ }else{ |
+ warning(line, "The dependency file %s does not exist. Please make sure it exists.\n",filename); |
+ } |
+ } |
+ if(dependencyArray==NULL){ |
+ dependencyArray = array_open(state->bundle, "%%DEPENDENCY", NULL, status); |
+ } |
+ if(tag!=NULL){ |
+ result = string_open(state->bundle, tag, tokenValue->fChars, tokenValue->fLength, comment, status); |
+ } |
+ elem = string_open(state->bundle, NULL, tokenValue->fChars, tokenValue->fLength, comment, status); |
+ |
+ array_add(dependencyArray, elem, status); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ return NULL; |
+ } |
+ expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status); |
+ return result; |
+} |
+static struct SResource * |
+parseString(ParseState* state, char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status) |
+{ |
+ struct UString *tokenValue; |
+ struct SResource *result = NULL; |
+ |
+/* if (tag != NULL && uprv_strcmp(tag, "%%UCARULES") == 0) |
+ { |
+ return parseUCARules(tag, startline, status); |
+ }*/ |
+ if(isVerbose()){ |
+ printf(" string %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline); |
+ } |
+ expect(state, TOK_STRING, &tokenValue, NULL, NULL, status); |
+ |
+ if (U_SUCCESS(*status)) |
+ { |
+ /* create the string now - tokenValue doesn't survive a call to getToken (and therefore |
+ doesn't survive expect either) */ |
+ |
+ result = string_open(state->bundle, tag, tokenValue->fChars, tokenValue->fLength, comment, status); |
+ if(U_SUCCESS(*status) && result) { |
+ expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ res_close(result); |
+ return NULL; |
+ } |
+ } |
+ } |
+ |
+ return result; |
+} |
+ |
+static struct SResource * |
+parseAlias(ParseState* state, char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status) |
+{ |
+ struct UString *tokenValue; |
+ struct SResource *result = NULL; |
+ |
+ expect(state, TOK_STRING, &tokenValue, NULL, NULL, status); |
+ |
+ if(isVerbose()){ |
+ printf(" alias %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline); |
+ } |
+ |
+ if (U_SUCCESS(*status)) |
+ { |
+ /* create the string now - tokenValue doesn't survive a call to getToken (and therefore |
+ doesn't survive expect either) */ |
+ |
+ result = alias_open(state->bundle, tag, tokenValue->fChars, tokenValue->fLength, comment, status); |
+ |
+ expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ res_close(result); |
+ return NULL; |
+ } |
+ } |
+ |
+ return result; |
+} |
+ |
+typedef struct{ |
+ const char* inputDir; |
+ const char* outputDir; |
+} GenrbData; |
+ |
+static struct SResource* resLookup(struct SResource* res, const char* key){ |
+ struct SResource *current = NULL; |
+ struct SResTable *list; |
+ if (res == res_none()) { |
+ return NULL; |
+ } |
+ |
+ list = &(res->u.fTable); |
+ |
+ current = list->fFirst; |
+ while (current != NULL) { |
+ if (uprv_strcmp(((list->fRoot->fKeys) + (current->fKey)), key) == 0) { |
+ return current; |
+ } |
+ current = current->fNext; |
+ } |
+ return NULL; |
+} |
+ |
+static const UChar* importFromDataFile(void* context, const char* locale, const char* type, int32_t* pLength, UErrorCode* status){ |
+ struct SRBRoot *data = NULL; |
+ UCHARBUF *ucbuf = NULL; |
+ GenrbData* genrbdata = (GenrbData*) context; |
+ int localeLength = strlen(locale); |
+ char* filename = (char*)uprv_malloc(localeLength+5); |
+ char *inputDirBuf = NULL; |
+ char *openFileName = NULL; |
+ const char* cp = ""; |
+ UChar* urules = NULL; |
+ int32_t urulesLength = 0; |
+ int32_t i = 0; |
+ int32_t dirlen = 0; |
+ int32_t filelen = 0; |
+ struct SResource* root; |
+ struct SResource* collations; |
+ struct SResource* collation; |
+ struct SResource* sequence; |
+ |
+ memcpy(filename, locale, localeLength); |
+ for(i = 0; i < localeLength; i++){ |
+ if(filename[i] == '-'){ |
+ filename[i] = '_'; |
+ } |
+ } |
+ filename[localeLength] = '.'; |
+ filename[localeLength+1] = 't'; |
+ filename[localeLength+2] = 'x'; |
+ filename[localeLength+3] = 't'; |
+ filename[localeLength+4] = 0; |
+ |
+ |
+ if (status==NULL || U_FAILURE(*status)) { |
+ return NULL; |
+ } |
+ if(filename==NULL){ |
+ *status=U_ILLEGAL_ARGUMENT_ERROR; |
+ return NULL; |
+ }else{ |
+ filelen = (int32_t)uprv_strlen(filename); |
+ } |
+ if(genrbdata->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; |
+ genrbdata->inputDir = inputDirBuf; |
+ dirlen = (int32_t)uprv_strlen(genrbdata->inputDir); |
+ } |
+ }else{ |
+ dirlen = (int32_t)uprv_strlen(genrbdata->inputDir); |
+ |
+ if(genrbdata->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) && (genrbdata->inputDir[dirlen-1] !='.')){ |
+ uprv_strcpy(openFileName, genrbdata->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, genrbdata->inputDir); |
+ |
+ } |
+ } |
+ uprv_strcat(openFileName, filename); |
+ /* printf("%s\n", openFileName); */ |
+ *status = U_ZERO_ERROR; |
+ 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; |
+ } |
+ |
+ /* Parse the data into an SRBRoot */ |
+ data = parse(ucbuf, genrbdata->inputDir, genrbdata->outputDir, status); |
+ |
+ root = data->fRoot; |
+ collations = resLookup(root, "collations"); |
+ collation = resLookup(collations, type); |
+ sequence = resLookup(collation, "Sequence"); |
+ urules = sequence->u.fString.fChars; |
+ urulesLength = sequence->u.fString.fLength; |
+ *pLength = urulesLength; |
+ |
+finish: |
+ |
+ if (inputDirBuf != NULL) { |
+ uprv_free(inputDirBuf); |
+ } |
+ |
+ if (openFileName != NULL) { |
+ uprv_free(openFileName); |
+ } |
+ |
+ if(ucbuf) { |
+ ucbuf_close(ucbuf); |
+ } |
+ |
+ return urules; |
+} |
+ |
+static struct SResource * |
+addCollation(ParseState* state, struct SResource *result, uint32_t startline, UErrorCode *status) |
+{ |
+ struct SResource *member = NULL; |
+ struct UString *tokenValue; |
+ struct UString comment; |
+ enum ETokenType token; |
+ char subtag[1024]; |
+ UVersionInfo version; |
+ UBool override = FALSE; |
+ uint32_t line; |
+ GenrbData genrbdata; |
+ /* '{' . (name resource)* '}' */ |
+ version[0]=0; version[1]=0; version[2]=0; version[3]=0; |
+ |
+ for (;;) |
+ { |
+ ustr_init(&comment); |
+ token = getToken(state, &tokenValue, &comment, &line, status); |
+ |
+ if (token == TOK_CLOSE_BRACE) |
+ { |
+ return result; |
+ } |
+ |
+ if (token != TOK_STRING) |
+ { |
+ res_close(result); |
+ *status = U_INVALID_FORMAT_ERROR; |
+ |
+ if (token == TOK_EOF) |
+ { |
+ error(startline, "unterminated table"); |
+ } |
+ else |
+ { |
+ error(line, "Unexpected token %s", tokenNames[token]); |
+ } |
+ |
+ return NULL; |
+ } |
+ |
+ u_UCharsToChars(tokenValue->fChars, subtag, u_strlen(tokenValue->fChars) + 1); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ res_close(result); |
+ return NULL; |
+ } |
+ |
+ member = parseResource(state, subtag, NULL, status); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ res_close(result); |
+ return NULL; |
+ } |
+ |
+ if (uprv_strcmp(subtag, "Version") == 0) |
+ { |
+ char ver[40]; |
+ int32_t length = member->u.fString.fLength; |
+ |
+ if (length >= (int32_t) sizeof(ver)) |
+ { |
+ length = (int32_t) sizeof(ver) - 1; |
+ } |
+ |
+ u_UCharsToChars(member->u.fString.fChars, ver, length + 1); /* +1 for copying NULL */ |
+ u_versionFromString(version, ver); |
+ |
+ table_add(result, member, line, status); |
+ |
+ } |
+ else if (uprv_strcmp(subtag, "Override") == 0) |
+ { |
+ override = FALSE; |
+ |
+ if (u_strncmp(member->u.fString.fChars, trueValue, u_strlen(trueValue)) == 0) |
+ { |
+ override = TRUE; |
+ } |
+ table_add(result, member, line, status); |
+ |
+ } |
+ else if(uprv_strcmp(subtag, "%%CollationBin")==0) |
+ { |
+ /* discard duplicate %%CollationBin if any*/ |
+ } |
+ else if (uprv_strcmp(subtag, "Sequence") == 0) |
+ { |
+#if UCONFIG_NO_COLLATION || UCONFIG_NO_FILE_IO |
+ warning(line, "Not building collation elements because of UCONFIG_NO_COLLATION and/or UCONFIG_NO_FILE_IO, see uconfig.h"); |
+#else |
+ if(gMakeBinaryCollation) { |
+ UErrorCode intStatus = U_ZERO_ERROR; |
+ |
+ /* do the collation elements */ |
+ int32_t len = 0; |
+ uint8_t *data = NULL; |
+ UCollator *coll = NULL; |
+ int32_t reorderCodes[USCRIPT_CODE_LIMIT + (UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST)]; |
+ uint32_t reorderCodeCount; |
+ int32_t reorderCodeIndex; |
+ UParseError parseError; |
+ |
+ genrbdata.inputDir = state->inputdir; |
+ genrbdata.outputDir = state->outputdir; |
+ |
+ coll = ucol_openRulesForImport(member->u.fString.fChars, member->u.fString.fLength, |
+ UCOL_OFF, UCOL_DEFAULT_STRENGTH,&parseError, importFromDataFile, &genrbdata, &intStatus); |
+ |
+ if (U_SUCCESS(intStatus) && coll != NULL) |
+ { |
+ len = ucol_cloneBinary(coll, NULL, 0, &intStatus); |
+ data = (uint8_t *)uprv_malloc(len); |
+ intStatus = U_ZERO_ERROR; |
+ len = ucol_cloneBinary(coll, data, len, &intStatus); |
+ /*data = ucol_cloneRuleData(coll, &len, &intStatus);*/ |
+ |
+ /* tailoring rules version */ |
+ /* This is wrong! */ |
+ /*coll->dataInfo.dataVersion[1] = version[0];*/ |
+ /* Copy tailoring version. Builder version already */ |
+ /* set in ucol_openRules */ |
+ ((UCATableHeader *)data)->version[1] = version[0]; |
+ ((UCATableHeader *)data)->version[2] = version[1]; |
+ ((UCATableHeader *)data)->version[3] = version[2]; |
+ |
+ if (U_SUCCESS(intStatus) && data != NULL) |
+ { |
+ struct SResource *collationBin = bin_open(state->bundle, "%%CollationBin", len, data, NULL, NULL, status); |
+ table_add(result, collationBin, line, status); |
+ uprv_free(data); |
+ |
+ reorderCodeCount = ucol_getReorderCodes( |
+ coll, reorderCodes, USCRIPT_CODE_LIMIT + (UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST), &intStatus); |
+ if (U_SUCCESS(intStatus) && reorderCodeCount > 0) { |
+ struct SResource *reorderCodeRes = intvector_open(state->bundle, "%%ReorderCodes", NULL, status); |
+ for (reorderCodeIndex = 0; reorderCodeIndex < reorderCodeCount; reorderCodeIndex++) { |
+ intvector_add(reorderCodeRes, reorderCodes[reorderCodeIndex], status); |
+ } |
+ table_add(result, reorderCodeRes, line, status); |
+ } |
+ } |
+ else |
+ { |
+ warning(line, "could not obtain rules from collator"); |
+ if(isStrict()){ |
+ *status = U_INVALID_FORMAT_ERROR; |
+ return NULL; |
+ } |
+ } |
+ |
+ ucol_close(coll); |
+ } |
+ else |
+ { |
+ if(intStatus == U_FILE_ACCESS_ERROR) { |
+ error(startline, "Collation could not be built- U_FILE_ACCESS_ERROR. Make sure ICU's data has been built and is loading properly."); |
+ *status = intStatus; |
+ return NULL; |
+ } |
+ warning(line, "%%Collation could not be constructed from CollationElements - check context!"); |
+ if(isStrict()){ |
+ *status = intStatus; |
+ return NULL; |
+ } |
+ } |
+ } else { |
+ if(isVerbose()) { |
+ printf("Not building Collation binary\n"); |
+ } |
+ } |
+#endif |
+ /* in order to achieve smaller data files, we can direct genrb */ |
+ /* to omit collation rules */ |
+ if(gOmitCollationRules) { |
+ bundle_closeString(state->bundle, member); |
+ } else { |
+ table_add(result, member, line, status); |
+ } |
+ } |
+ |
+ /*member = string_open(bundle, subtag, tokenValue->fChars, tokenValue->fLength, status);*/ |
+ |
+ /*expect(TOK_CLOSE_BRACE, NULL, NULL, status);*/ |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ res_close(result); |
+ return NULL; |
+ } |
+ } |
+ |
+ /* not reached */ |
+ /* A compiler warning will appear if all paths don't contain a return statement. */ |
+/* *status = U_INTERNAL_PROGRAM_ERROR; |
+ return NULL;*/ |
+} |
+ |
+static struct SResource * |
+parseCollationElements(ParseState* state, char *tag, uint32_t startline, UBool newCollation, UErrorCode *status) |
+{ |
+ struct SResource *result = NULL; |
+ struct SResource *member = NULL; |
+ struct SResource *collationRes = NULL; |
+ struct UString *tokenValue; |
+ struct UString comment; |
+ enum ETokenType token; |
+ char subtag[1024], typeKeyword[1024]; |
+ uint32_t line; |
+ |
+ result = table_open(state->bundle, tag, NULL, status); |
+ |
+ if (result == NULL || U_FAILURE(*status)) |
+ { |
+ return NULL; |
+ } |
+ if(isVerbose()){ |
+ printf(" collation elements %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline); |
+ } |
+ if(!newCollation) { |
+ return addCollation(state, result, startline, status); |
+ } |
+ else { |
+ for(;;) { |
+ ustr_init(&comment); |
+ token = getToken(state, &tokenValue, &comment, &line, status); |
+ |
+ if (token == TOK_CLOSE_BRACE) |
+ { |
+ return result; |
+ } |
+ |
+ if (token != TOK_STRING) |
+ { |
+ res_close(result); |
+ *status = U_INVALID_FORMAT_ERROR; |
+ |
+ if (token == TOK_EOF) |
+ { |
+ error(startline, "unterminated table"); |
+ } |
+ else |
+ { |
+ error(line, "Unexpected token %s", tokenNames[token]); |
+ } |
+ |
+ return NULL; |
+ } |
+ |
+ u_UCharsToChars(tokenValue->fChars, subtag, u_strlen(tokenValue->fChars) + 1); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ res_close(result); |
+ return NULL; |
+ } |
+ |
+ if (uprv_strcmp(subtag, "default") == 0) |
+ { |
+ member = parseResource(state, subtag, NULL, status); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ res_close(result); |
+ return NULL; |
+ } |
+ |
+ table_add(result, member, line, status); |
+ } |
+ else |
+ { |
+ token = peekToken(state, 0, &tokenValue, &line, &comment, status); |
+ /* this probably needs to be refactored or recursively use the parser */ |
+ /* first we assume that our collation table won't have the explicit type */ |
+ /* then, we cannot handle aliases */ |
+ if(token == TOK_OPEN_BRACE) { |
+ token = getToken(state, &tokenValue, &comment, &line, status); |
+ collationRes = table_open(state->bundle, subtag, NULL, status); |
+ collationRes = addCollation(state, collationRes, startline, status); /* need to parse the collation data regardless */ |
+ if (gIncludeUnihanColl || uprv_strcmp(subtag, "unihan") != 0) { |
+ table_add(result, collationRes, startline, status); |
+ } |
+ } else if(token == TOK_COLON) { /* right now, we'll just try to see if we have aliases */ |
+ /* we could have a table too */ |
+ token = peekToken(state, 1, &tokenValue, &line, &comment, status); |
+ u_UCharsToChars(tokenValue->fChars, typeKeyword, u_strlen(tokenValue->fChars) + 1); |
+ if(uprv_strcmp(typeKeyword, "alias") == 0) { |
+ member = parseResource(state, subtag, NULL, status); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ res_close(result); |
+ return NULL; |
+ } |
+ |
+ table_add(result, member, line, status); |
+ } else { |
+ res_close(result); |
+ *status = U_INVALID_FORMAT_ERROR; |
+ return NULL; |
+ } |
+ } else { |
+ res_close(result); |
+ *status = U_INVALID_FORMAT_ERROR; |
+ return NULL; |
+ } |
+ } |
+ |
+ /*member = string_open(bundle, subtag, tokenValue->fChars, tokenValue->fLength, status);*/ |
+ |
+ /*expect(TOK_CLOSE_BRACE, NULL, NULL, status);*/ |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ res_close(result); |
+ return NULL; |
+ } |
+ } |
+ } |
+} |
+ |
+/* Necessary, because CollationElements requires the bundle->fRoot member to be present which, |
+ if this weren't special-cased, wouldn't be set until the entire file had been processed. */ |
+static struct SResource * |
+realParseTable(ParseState* state, struct SResource *table, char *tag, uint32_t startline, UErrorCode *status) |
+{ |
+ struct SResource *member = NULL; |
+ struct UString *tokenValue=NULL; |
+ struct UString comment; |
+ enum ETokenType token; |
+ char subtag[1024]; |
+ uint32_t line; |
+ UBool readToken = FALSE; |
+ |
+ /* '{' . (name resource)* '}' */ |
+ if(isVerbose()){ |
+ printf(" parsing table %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline); |
+ } |
+ for (;;) |
+ { |
+ ustr_init(&comment); |
+ token = getToken(state, &tokenValue, &comment, &line, status); |
+ |
+ if (token == TOK_CLOSE_BRACE) |
+ { |
+ if (!readToken) { |
+ warning(startline, "Encountered empty table"); |
+ } |
+ return table; |
+ } |
+ |
+ if (token != TOK_STRING) |
+ { |
+ *status = U_INVALID_FORMAT_ERROR; |
+ |
+ if (token == TOK_EOF) |
+ { |
+ error(startline, "unterminated table"); |
+ } |
+ else |
+ { |
+ error(line, "unexpected token %s", tokenNames[token]); |
+ } |
+ |
+ return NULL; |
+ } |
+ |
+ if(uprv_isInvariantUString(tokenValue->fChars, -1)) { |
+ u_UCharsToChars(tokenValue->fChars, subtag, u_strlen(tokenValue->fChars) + 1); |
+ } else { |
+ *status = U_INVALID_FORMAT_ERROR; |
+ error(line, "invariant characters required for table keys"); |
+ return NULL; |
+ } |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ error(line, "parse error. Stopped parsing tokens with %s", u_errorName(*status)); |
+ return NULL; |
+ } |
+ |
+ member = parseResource(state, subtag, &comment, status); |
+ |
+ if (member == NULL || U_FAILURE(*status)) |
+ { |
+ error(line, "parse error. Stopped parsing resource with %s", u_errorName(*status)); |
+ return NULL; |
+ } |
+ |
+ table_add(table, member, line, status); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ error(line, "parse error. Stopped parsing table with %s", u_errorName(*status)); |
+ return NULL; |
+ } |
+ readToken = TRUE; |
+ ustr_deinit(&comment); |
+ } |
+ |
+ /* not reached */ |
+ /* A compiler warning will appear if all paths don't contain a return statement. */ |
+/* *status = U_INTERNAL_PROGRAM_ERROR; |
+ return NULL;*/ |
+} |
+ |
+static struct SResource * |
+parseTable(ParseState* state, char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status) |
+{ |
+ struct SResource *result; |
+ |
+ if (tag != NULL && uprv_strcmp(tag, "CollationElements") == 0) |
+ { |
+ return parseCollationElements(state, tag, startline, FALSE, status); |
+ } |
+ if (tag != NULL && uprv_strcmp(tag, "collations") == 0) |
+ { |
+ return parseCollationElements(state, tag, startline, TRUE, status); |
+ } |
+ if(isVerbose()){ |
+ printf(" table %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline); |
+ } |
+ |
+ result = table_open(state->bundle, tag, comment, status); |
+ |
+ if (result == NULL || U_FAILURE(*status)) |
+ { |
+ return NULL; |
+ } |
+ |
+ return realParseTable(state, result, tag, startline, status); |
+} |
+ |
+static struct SResource * |
+parseArray(ParseState* state, char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status) |
+{ |
+ struct SResource *result = NULL; |
+ struct SResource *member = NULL; |
+ struct UString *tokenValue; |
+ struct UString memberComments; |
+ enum ETokenType token; |
+ UBool readToken = FALSE; |
+ |
+ result = array_open(state->bundle, tag, comment, status); |
+ |
+ if (result == NULL || U_FAILURE(*status)) |
+ { |
+ return NULL; |
+ } |
+ if(isVerbose()){ |
+ printf(" array %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline); |
+ } |
+ |
+ ustr_init(&memberComments); |
+ |
+ /* '{' . resource [','] '}' */ |
+ for (;;) |
+ { |
+ /* reset length */ |
+ ustr_setlen(&memberComments, 0, status); |
+ |
+ /* check for end of array, but don't consume next token unless it really is the end */ |
+ token = peekToken(state, 0, &tokenValue, NULL, &memberComments, status); |
+ |
+ |
+ if (token == TOK_CLOSE_BRACE) |
+ { |
+ getToken(state, NULL, NULL, NULL, status); |
+ if (!readToken) { |
+ warning(startline, "Encountered empty array"); |
+ } |
+ break; |
+ } |
+ |
+ if (token == TOK_EOF) |
+ { |
+ res_close(result); |
+ *status = U_INVALID_FORMAT_ERROR; |
+ error(startline, "unterminated array"); |
+ return NULL; |
+ } |
+ |
+ /* string arrays are a special case */ |
+ if (token == TOK_STRING) |
+ { |
+ getToken(state, &tokenValue, &memberComments, NULL, status); |
+ member = string_open(state->bundle, NULL, tokenValue->fChars, tokenValue->fLength, &memberComments, status); |
+ } |
+ else |
+ { |
+ member = parseResource(state, NULL, &memberComments, status); |
+ } |
+ |
+ if (member == NULL || U_FAILURE(*status)) |
+ { |
+ res_close(result); |
+ return NULL; |
+ } |
+ |
+ array_add(result, member, status); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ res_close(result); |
+ return NULL; |
+ } |
+ |
+ /* eat optional comma if present */ |
+ token = peekToken(state, 0, NULL, NULL, NULL, status); |
+ |
+ if (token == TOK_COMMA) |
+ { |
+ getToken(state, NULL, NULL, NULL, status); |
+ } |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ res_close(result); |
+ return NULL; |
+ } |
+ readToken = TRUE; |
+ } |
+ |
+ ustr_deinit(&memberComments); |
+ return result; |
+} |
+ |
+static struct SResource * |
+parseIntVector(ParseState* state, char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status) |
+{ |
+ struct SResource *result = NULL; |
+ enum ETokenType token; |
+ char *string; |
+ int32_t value; |
+ UBool readToken = FALSE; |
+ char *stopstring; |
+ uint32_t len; |
+ struct UString memberComments; |
+ |
+ result = intvector_open(state->bundle, tag, comment, status); |
+ |
+ if (result == NULL || U_FAILURE(*status)) |
+ { |
+ return NULL; |
+ } |
+ |
+ if(isVerbose()){ |
+ printf(" vector %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline); |
+ } |
+ ustr_init(&memberComments); |
+ /* '{' . string [','] '}' */ |
+ for (;;) |
+ { |
+ ustr_setlen(&memberComments, 0, status); |
+ |
+ /* check for end of array, but don't consume next token unless it really is the end */ |
+ token = peekToken(state, 0, NULL, NULL,&memberComments, status); |
+ |
+ if (token == TOK_CLOSE_BRACE) |
+ { |
+ /* it's the end, consume the close brace */ |
+ getToken(state, NULL, NULL, NULL, status); |
+ if (!readToken) { |
+ warning(startline, "Encountered empty int vector"); |
+ } |
+ ustr_deinit(&memberComments); |
+ return result; |
+ } |
+ |
+ string = getInvariantString(state, NULL, NULL, status); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ res_close(result); |
+ return NULL; |
+ } |
+ |
+ /* For handling illegal char in the Intvector */ |
+ value = uprv_strtoul(string, &stopstring, 0);/* make intvector support decimal,hexdigit,octal digit ranging from -2^31-2^32-1*/ |
+ len=(uint32_t)(stopstring-string); |
+ |
+ if(len==uprv_strlen(string)) |
+ { |
+ intvector_add(result, value, status); |
+ uprv_free(string); |
+ token = peekToken(state, 0, NULL, NULL, NULL, status); |
+ } |
+ else |
+ { |
+ uprv_free(string); |
+ *status=U_INVALID_CHAR_FOUND; |
+ } |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ res_close(result); |
+ return NULL; |
+ } |
+ |
+ /* the comma is optional (even though it is required to prevent the reader from concatenating |
+ consecutive entries) so that a missing comma on the last entry isn't an error */ |
+ if (token == TOK_COMMA) |
+ { |
+ getToken(state, NULL, NULL, NULL, status); |
+ } |
+ readToken = TRUE; |
+ } |
+ |
+ /* not reached */ |
+ /* A compiler warning will appear if all paths don't contain a return statement. */ |
+/* intvector_close(result, status); |
+ *status = U_INTERNAL_PROGRAM_ERROR; |
+ return NULL;*/ |
+} |
+ |
+static struct SResource * |
+parseBinary(ParseState* state, char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status) |
+{ |
+ struct SResource *result = NULL; |
+ uint8_t *value; |
+ char *string; |
+ char toConv[3] = {'\0', '\0', '\0'}; |
+ uint32_t count; |
+ uint32_t i; |
+ uint32_t line; |
+ char *stopstring; |
+ uint32_t len; |
+ |
+ string = getInvariantString(state, &line, NULL, status); |
+ |
+ if (string == NULL || U_FAILURE(*status)) |
+ { |
+ return NULL; |
+ } |
+ |
+ expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ uprv_free(string); |
+ return NULL; |
+ } |
+ |
+ if(isVerbose()){ |
+ printf(" binary %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline); |
+ } |
+ |
+ count = (uint32_t)uprv_strlen(string); |
+ if (count > 0){ |
+ if((count % 2)==0){ |
+ value = uprv_malloc(sizeof(uint8_t) * count); |
+ |
+ if (value == NULL) |
+ { |
+ uprv_free(string); |
+ *status = U_MEMORY_ALLOCATION_ERROR; |
+ return NULL; |
+ } |
+ |
+ for (i = 0; i < count; i += 2) |
+ { |
+ toConv[0] = string[i]; |
+ toConv[1] = string[i + 1]; |
+ |
+ value[i >> 1] = (uint8_t) uprv_strtoul(toConv, &stopstring, 16); |
+ len=(uint32_t)(stopstring-toConv); |
+ |
+ if(len!=uprv_strlen(toConv)) |
+ { |
+ uprv_free(string); |
+ *status=U_INVALID_CHAR_FOUND; |
+ return NULL; |
+ } |
+ } |
+ |
+ result = bin_open(state->bundle, tag, (i >> 1), value,NULL, comment, status); |
+ |
+ uprv_free(value); |
+ } |
+ else |
+ { |
+ *status = U_INVALID_CHAR_FOUND; |
+ uprv_free(string); |
+ error(line, "Encountered invalid binary string"); |
+ return NULL; |
+ } |
+ } |
+ else |
+ { |
+ result = bin_open(state->bundle, tag, 0, NULL, "",comment,status); |
+ warning(startline, "Encountered empty binary tag"); |
+ } |
+ uprv_free(string); |
+ |
+ return result; |
+} |
+ |
+static struct SResource * |
+parseInteger(ParseState* state, char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status) |
+{ |
+ struct SResource *result = NULL; |
+ int32_t value; |
+ char *string; |
+ char *stopstring; |
+ uint32_t len; |
+ |
+ string = getInvariantString(state, NULL, NULL, status); |
+ |
+ if (string == NULL || U_FAILURE(*status)) |
+ { |
+ return NULL; |
+ } |
+ |
+ expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ uprv_free(string); |
+ return NULL; |
+ } |
+ |
+ if(isVerbose()){ |
+ printf(" integer %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline); |
+ } |
+ |
+ if (uprv_strlen(string) <= 0) |
+ { |
+ warning(startline, "Encountered empty integer. Default value is 0."); |
+ } |
+ |
+ /* Allow integer support for hexdecimal, octal digit and decimal*/ |
+ /* and handle illegal char in the integer*/ |
+ value = uprv_strtoul(string, &stopstring, 0); |
+ len=(uint32_t)(stopstring-string); |
+ if(len==uprv_strlen(string)) |
+ { |
+ result = int_open(state->bundle, tag, value, comment, status); |
+ } |
+ else |
+ { |
+ *status=U_INVALID_CHAR_FOUND; |
+ } |
+ uprv_free(string); |
+ |
+ return result; |
+} |
+ |
+static struct SResource * |
+parseImport(ParseState* state, char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status) |
+{ |
+ struct SResource *result; |
+ FileStream *file; |
+ int32_t len; |
+ uint8_t *data; |
+ char *filename; |
+ uint32_t line; |
+ char *fullname = NULL; |
+ int32_t numRead = 0; |
+ filename = getInvariantString(state, &line, NULL, status); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ return NULL; |
+ } |
+ |
+ expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ uprv_free(filename); |
+ return NULL; |
+ } |
+ |
+ if(isVerbose()){ |
+ printf(" import %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline); |
+ } |
+ |
+ /* Open the input file for reading */ |
+ if (state->inputdir == NULL) |
+ { |
+#if 1 |
+ /* |
+ * Always save file file name, even if there's |
+ * no input directory specified. MIGHT BREAK SOMETHING |
+ */ |
+ int32_t filenameLength = uprv_strlen(filename); |
+ |
+ fullname = (char *) uprv_malloc(filenameLength + 1); |
+ uprv_strcpy(fullname, filename); |
+#endif |
+ |
+ file = T_FileStream_open(filename, "rb"); |
+ } |
+ else |
+ { |
+ |
+ int32_t count = (int32_t)uprv_strlen(filename); |
+ |
+ if (state->inputdir[state->inputdirLength - 1] != U_FILE_SEP_CHAR) |
+ { |
+ fullname = (char *) uprv_malloc(state->inputdirLength + count + 2); |
+ |
+ /* test for NULL */ |
+ if(fullname == NULL) |
+ { |
+ *status = U_MEMORY_ALLOCATION_ERROR; |
+ return NULL; |
+ } |
+ |
+ uprv_strcpy(fullname, state->inputdir); |
+ |
+ fullname[state->inputdirLength] = U_FILE_SEP_CHAR; |
+ fullname[state->inputdirLength + 1] = '\0'; |
+ |
+ uprv_strcat(fullname, filename); |
+ } |
+ else |
+ { |
+ fullname = (char *) uprv_malloc(state->inputdirLength + count + 1); |
+ |
+ /* test for NULL */ |
+ if(fullname == NULL) |
+ { |
+ *status = U_MEMORY_ALLOCATION_ERROR; |
+ return NULL; |
+ } |
+ |
+ uprv_strcpy(fullname, state->inputdir); |
+ uprv_strcat(fullname, filename); |
+ } |
+ |
+ file = T_FileStream_open(fullname, "rb"); |
+ |
+ } |
+ |
+ if (file == NULL) |
+ { |
+ error(line, "couldn't open input file %s", filename); |
+ *status = U_FILE_ACCESS_ERROR; |
+ return NULL; |
+ } |
+ |
+ len = T_FileStream_size(file); |
+ data = (uint8_t*)uprv_malloc(len * sizeof(uint8_t)); |
+ /* test for NULL */ |
+ if(data == NULL) |
+ { |
+ *status = U_MEMORY_ALLOCATION_ERROR; |
+ T_FileStream_close (file); |
+ return NULL; |
+ } |
+ |
+ numRead = T_FileStream_read (file, data, len); |
+ T_FileStream_close (file); |
+ |
+ result = bin_open(state->bundle, tag, len, data, fullname, comment, status); |
+ |
+ uprv_free(data); |
+ uprv_free(filename); |
+ uprv_free(fullname); |
+ |
+ return result; |
+} |
+ |
+static struct SResource * |
+parseInclude(ParseState* state, char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status) |
+{ |
+ struct SResource *result; |
+ int32_t len=0; |
+ char *filename; |
+ uint32_t line; |
+ UChar *pTarget = NULL; |
+ |
+ UCHARBUF *ucbuf; |
+ char *fullname = NULL; |
+ int32_t count = 0; |
+ const char* cp = NULL; |
+ const UChar* uBuffer = NULL; |
+ |
+ filename = getInvariantString(state, &line, NULL, status); |
+ count = (int32_t)uprv_strlen(filename); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ return NULL; |
+ } |
+ |
+ expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ uprv_free(filename); |
+ return NULL; |
+ } |
+ |
+ if(isVerbose()){ |
+ printf(" include %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline); |
+ } |
+ |
+ fullname = (char *) uprv_malloc(state->inputdirLength + count + 2); |
+ /* test for NULL */ |
+ if(fullname == NULL) |
+ { |
+ *status = U_MEMORY_ALLOCATION_ERROR; |
+ uprv_free(filename); |
+ return NULL; |
+ } |
+ |
+ if(state->inputdir!=NULL){ |
+ if (state->inputdir[state->inputdirLength - 1] != U_FILE_SEP_CHAR) |
+ { |
+ |
+ uprv_strcpy(fullname, state->inputdir); |
+ |
+ fullname[state->inputdirLength] = U_FILE_SEP_CHAR; |
+ fullname[state->inputdirLength + 1] = '\0'; |
+ |
+ uprv_strcat(fullname, filename); |
+ } |
+ else |
+ { |
+ uprv_strcpy(fullname, state->inputdir); |
+ uprv_strcat(fullname, filename); |
+ } |
+ }else{ |
+ uprv_strcpy(fullname,filename); |
+ } |
+ |
+ ucbuf = ucbuf_open(fullname, &cp,getShowWarning(),FALSE,status); |
+ |
+ if (U_FAILURE(*status)) { |
+ error(line, "couldn't open input file %s\n", filename); |
+ return NULL; |
+ } |
+ |
+ uBuffer = ucbuf_getBuffer(ucbuf,&len,status); |
+ result = string_open(state->bundle, tag, uBuffer, len, comment, status); |
+ |
+ uprv_free(pTarget); |
+ |
+ uprv_free(filename); |
+ uprv_free(fullname); |
+ |
+ return result; |
+} |
+ |
+ |
+ |
+ |
+ |
+U_STRING_DECL(k_type_string, "string", 6); |
+U_STRING_DECL(k_type_binary, "binary", 6); |
+U_STRING_DECL(k_type_bin, "bin", 3); |
+U_STRING_DECL(k_type_table, "table", 5); |
+U_STRING_DECL(k_type_table_no_fallback, "table(nofallback)", 17); |
+U_STRING_DECL(k_type_int, "int", 3); |
+U_STRING_DECL(k_type_integer, "integer", 7); |
+U_STRING_DECL(k_type_array, "array", 5); |
+U_STRING_DECL(k_type_alias, "alias", 5); |
+U_STRING_DECL(k_type_intvector, "intvector", 9); |
+U_STRING_DECL(k_type_import, "import", 6); |
+U_STRING_DECL(k_type_include, "include", 7); |
+U_STRING_DECL(k_type_reserved, "reserved", 8); |
+ |
+/* Various non-standard processing plugins that create one or more special resources. */ |
+U_STRING_DECL(k_type_plugin_uca_rules, "process(uca_rules)", 18); |
+U_STRING_DECL(k_type_plugin_collation, "process(collation)", 18); |
+U_STRING_DECL(k_type_plugin_transliterator, "process(transliterator)", 23); |
+U_STRING_DECL(k_type_plugin_dependency, "process(dependency)", 19); |
+ |
+typedef enum EResourceType |
+{ |
+ RT_UNKNOWN, |
+ RT_STRING, |
+ RT_BINARY, |
+ RT_TABLE, |
+ RT_TABLE_NO_FALLBACK, |
+ RT_INTEGER, |
+ RT_ARRAY, |
+ RT_ALIAS, |
+ RT_INTVECTOR, |
+ RT_IMPORT, |
+ RT_INCLUDE, |
+ RT_PROCESS_UCA_RULES, |
+ RT_PROCESS_COLLATION, |
+ RT_PROCESS_TRANSLITERATOR, |
+ RT_PROCESS_DEPENDENCY, |
+ RT_RESERVED |
+} EResourceType; |
+ |
+static struct { |
+ const char *nameChars; /* only used for debugging */ |
+ const UChar *nameUChars; |
+ ParseResourceFunction *parseFunction; |
+} gResourceTypes[] = { |
+ {"Unknown", NULL, NULL}, |
+ {"string", k_type_string, parseString}, |
+ {"binary", k_type_binary, parseBinary}, |
+ {"table", k_type_table, parseTable}, |
+ {"table(nofallback)", k_type_table_no_fallback, NULL}, /* parseFunction will never be called */ |
+ {"integer", k_type_integer, parseInteger}, |
+ {"array", k_type_array, parseArray}, |
+ {"alias", k_type_alias, parseAlias}, |
+ {"intvector", k_type_intvector, parseIntVector}, |
+ {"import", k_type_import, parseImport}, |
+ {"include", k_type_include, parseInclude}, |
+ {"process(uca_rules)", k_type_plugin_uca_rules, parseUCARules}, |
+ {"process(collation)", k_type_plugin_collation, NULL /* not implemented yet */}, |
+ {"process(transliterator)", k_type_plugin_transliterator, parseTransliterator}, |
+ {"process(dependency)", k_type_plugin_dependency, parseDependency}, |
+ {"reserved", NULL, NULL} |
+}; |
+ |
+void initParser(UBool omitBinaryCollation, UBool omitCollationRules) |
+{ |
+ U_STRING_INIT(k_type_string, "string", 6); |
+ U_STRING_INIT(k_type_binary, "binary", 6); |
+ U_STRING_INIT(k_type_bin, "bin", 3); |
+ U_STRING_INIT(k_type_table, "table", 5); |
+ U_STRING_INIT(k_type_table_no_fallback, "table(nofallback)", 17); |
+ U_STRING_INIT(k_type_int, "int", 3); |
+ U_STRING_INIT(k_type_integer, "integer", 7); |
+ U_STRING_INIT(k_type_array, "array", 5); |
+ U_STRING_INIT(k_type_alias, "alias", 5); |
+ U_STRING_INIT(k_type_intvector, "intvector", 9); |
+ U_STRING_INIT(k_type_import, "import", 6); |
+ U_STRING_INIT(k_type_reserved, "reserved", 8); |
+ U_STRING_INIT(k_type_include, "include", 7); |
+ |
+ U_STRING_INIT(k_type_plugin_uca_rules, "process(uca_rules)", 18); |
+ U_STRING_INIT(k_type_plugin_collation, "process(collation)", 18); |
+ U_STRING_INIT(k_type_plugin_transliterator, "process(transliterator)", 23); |
+ U_STRING_INIT(k_type_plugin_dependency, "process(dependency)", 19); |
+ |
+ gMakeBinaryCollation = !omitBinaryCollation; |
+ gOmitCollationRules = omitCollationRules; |
+} |
+ |
+static U_INLINE UBool isTable(enum EResourceType type) { |
+ return (UBool)(type==RT_TABLE || type==RT_TABLE_NO_FALLBACK); |
+} |
+ |
+static enum EResourceType |
+parseResourceType(ParseState* state, UErrorCode *status) |
+{ |
+ struct UString *tokenValue; |
+ struct UString comment; |
+ enum EResourceType result = RT_UNKNOWN; |
+ uint32_t line=0; |
+ ustr_init(&comment); |
+ expect(state, TOK_STRING, &tokenValue, &comment, &line, status); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ return RT_UNKNOWN; |
+ } |
+ |
+ *status = U_ZERO_ERROR; |
+ |
+ /* Search for normal types */ |
+ result=RT_UNKNOWN; |
+ while (++result < RT_RESERVED) { |
+ if (u_strcmp(tokenValue->fChars, gResourceTypes[result].nameUChars) == 0) { |
+ break; |
+ } |
+ } |
+ /* Now search for the aliases */ |
+ if (u_strcmp(tokenValue->fChars, k_type_int) == 0) { |
+ result = RT_INTEGER; |
+ } |
+ else if (u_strcmp(tokenValue->fChars, k_type_bin) == 0) { |
+ result = RT_BINARY; |
+ } |
+ else if (result == RT_RESERVED) { |
+ char tokenBuffer[1024]; |
+ u_austrncpy(tokenBuffer, tokenValue->fChars, sizeof(tokenBuffer)); |
+ tokenBuffer[sizeof(tokenBuffer) - 1] = 0; |
+ *status = U_INVALID_FORMAT_ERROR; |
+ error(line, "unknown resource type '%s'", tokenBuffer); |
+ } |
+ |
+ return result; |
+} |
+ |
+/* parse a non-top-level resource */ |
+static struct SResource * |
+parseResource(ParseState* state, char *tag, const struct UString *comment, UErrorCode *status) |
+{ |
+ enum ETokenType token; |
+ enum EResourceType resType = RT_UNKNOWN; |
+ ParseResourceFunction *parseFunction = NULL; |
+ struct UString *tokenValue; |
+ uint32_t startline; |
+ uint32_t line; |
+ |
+ token = getToken(state, &tokenValue, NULL, &startline, status); |
+ |
+ if(isVerbose()){ |
+ printf(" resource %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline); |
+ } |
+ |
+ /* name . [ ':' type ] '{' resource '}' */ |
+ /* This function parses from the colon onwards. If the colon is present, parse the |
+ type then try to parse a resource of that type. If there is no explicit type, |
+ work it out using the lookahead tokens. */ |
+ switch (token) |
+ { |
+ case TOK_EOF: |
+ *status = U_INVALID_FORMAT_ERROR; |
+ error(startline, "Unexpected EOF encountered"); |
+ return NULL; |
+ |
+ case TOK_ERROR: |
+ *status = U_INVALID_FORMAT_ERROR; |
+ return NULL; |
+ |
+ case TOK_COLON: |
+ resType = parseResourceType(state, status); |
+ expect(state, TOK_OPEN_BRACE, &tokenValue, NULL, &startline, status); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ return NULL; |
+ } |
+ |
+ break; |
+ |
+ case TOK_OPEN_BRACE: |
+ break; |
+ |
+ default: |
+ *status = U_INVALID_FORMAT_ERROR; |
+ error(startline, "syntax error while reading a resource, expected '{' or ':'"); |
+ return NULL; |
+ } |
+ |
+ if (resType == RT_UNKNOWN) |
+ { |
+ /* No explicit type, so try to work it out. At this point, we've read the first '{'. |
+ We could have any of the following: |
+ { { => array (nested) |
+ { :/} => array |
+ { string , => string array |
+ |
+ { string { => table |
+ |
+ { string :/{ => table |
+ { string } => string |
+ */ |
+ |
+ token = peekToken(state, 0, NULL, &line, NULL,status); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ return NULL; |
+ } |
+ |
+ if (token == TOK_OPEN_BRACE || token == TOK_COLON ||token ==TOK_CLOSE_BRACE ) |
+ { |
+ resType = RT_ARRAY; |
+ } |
+ else if (token == TOK_STRING) |
+ { |
+ token = peekToken(state, 1, NULL, &line, NULL, status); |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ return NULL; |
+ } |
+ |
+ switch (token) |
+ { |
+ case TOK_COMMA: resType = RT_ARRAY; break; |
+ case TOK_OPEN_BRACE: resType = RT_TABLE; break; |
+ case TOK_CLOSE_BRACE: resType = RT_STRING; break; |
+ case TOK_COLON: resType = RT_TABLE; break; |
+ default: |
+ *status = U_INVALID_FORMAT_ERROR; |
+ error(line, "Unexpected token after string, expected ',', '{' or '}'"); |
+ return NULL; |
+ } |
+ } |
+ else |
+ { |
+ *status = U_INVALID_FORMAT_ERROR; |
+ error(line, "Unexpected token after '{'"); |
+ return NULL; |
+ } |
+ |
+ /* printf("Type guessed as %s\n", resourceNames[resType]); */ |
+ } else if(resType == RT_TABLE_NO_FALLBACK) { |
+ *status = U_INVALID_FORMAT_ERROR; |
+ error(startline, "error: %s resource type not valid except on top bundle level", gResourceTypes[resType].nameChars); |
+ return NULL; |
+ } |
+ |
+ /* We should now know what we need to parse next, so call the appropriate parser |
+ function and return. */ |
+ parseFunction = gResourceTypes[resType].parseFunction; |
+ if (parseFunction != NULL) { |
+ return parseFunction(state, tag, startline, comment, status); |
+ } |
+ else { |
+ *status = U_INTERNAL_PROGRAM_ERROR; |
+ error(startline, "internal error: %s resource type found and not handled", gResourceTypes[resType].nameChars); |
+ } |
+ |
+ return NULL; |
+} |
+ |
+/* parse the top-level resource */ |
+struct SRBRoot * |
+parse(UCHARBUF *buf, const char *inputDir, const char *outputDir, UErrorCode *status) |
+{ |
+ struct UString *tokenValue; |
+ struct UString comment; |
+ uint32_t line; |
+ enum EResourceType bundleType; |
+ enum ETokenType token; |
+ ParseState state; |
+ uint32_t i; |
+ int encLength; |
+ char* enc; |
+ for (i = 0; i < MAX_LOOKAHEAD + 1; i++) |
+ { |
+ ustr_init(&state.lookahead[i].value); |
+ ustr_init(&state.lookahead[i].comment); |
+ } |
+ |
+ initLookahead(&state, buf, status); |
+ |
+ state.inputdir = inputDir; |
+ state.inputdirLength = (state.inputdir != NULL) ? (uint32_t)uprv_strlen(state.inputdir) : 0; |
+ state.outputdir = outputDir; |
+ state.outputdirLength = (state.outputdir != NULL) ? (uint32_t)uprv_strlen(state.outputdir) : 0; |
+ |
+ ustr_init(&comment); |
+ expect(&state, TOK_STRING, &tokenValue, &comment, NULL, status); |
+ |
+ state.bundle = bundle_open(&comment, FALSE, status); |
+ |
+ if (state.bundle == NULL || U_FAILURE(*status)) |
+ { |
+ return NULL; |
+ } |
+ |
+ |
+ bundle_setlocale(state.bundle, tokenValue->fChars, status); |
+ |
+ /* The following code is to make Empty bundle work no matter with :table specifer or not */ |
+ token = getToken(&state, NULL, NULL, &line, status); |
+ if(token==TOK_COLON) { |
+ *status=U_ZERO_ERROR; |
+ bundleType=parseResourceType(&state, status); |
+ |
+ if(isTable(bundleType)) |
+ { |
+ expect(&state, TOK_OPEN_BRACE, NULL, NULL, &line, status); |
+ } |
+ else |
+ { |
+ *status=U_PARSE_ERROR; |
+ /* printf("asdsdweqdasdad\n"); */ |
+ |
+ error(line, "parse error. Stopped parsing with %s", u_errorName(*status)); |
+ } |
+ } |
+ else |
+ { |
+ /* not a colon */ |
+ if(token==TOK_OPEN_BRACE) |
+ { |
+ *status=U_ZERO_ERROR; |
+ bundleType=RT_TABLE; |
+ } |
+ else |
+ { |
+ /* neither colon nor open brace */ |
+ *status=U_PARSE_ERROR; |
+ bundleType=RT_UNKNOWN; |
+ error(line, "parse error, did not find open-brace '{' or colon ':', stopped with %s", u_errorName(*status)); |
+ } |
+ } |
+ |
+ if (U_FAILURE(*status)) |
+ { |
+ bundle_close(state.bundle, status); |
+ return NULL; |
+ } |
+ |
+ if(bundleType==RT_TABLE_NO_FALLBACK) { |
+ /* |
+ * Parse a top-level table with the table(nofallback) declaration. |
+ * This is the same as a regular table, but also sets the |
+ * URES_ATT_NO_FALLBACK flag in indexes[URES_INDEX_ATTRIBUTES] . |
+ */ |
+ state.bundle->noFallback=TRUE; |
+ } |
+ /* top-level tables need not handle special table names like "collations" */ |
+ realParseTable(&state, state.bundle->fRoot, NULL, line, status); |
+ |
+ if(dependencyArray!=NULL){ |
+ table_add(state.bundle->fRoot, dependencyArray, 0, status); |
+ dependencyArray = NULL; |
+ } |
+ if (U_FAILURE(*status)) |
+ { |
+ bundle_close(state.bundle, status); |
+ res_close(dependencyArray); |
+ return NULL; |
+ } |
+ |
+ if (getToken(&state, NULL, NULL, &line, status) != TOK_EOF) |
+ { |
+ warning(line, "extraneous text after resource bundle (perhaps unmatched braces)"); |
+ if(isStrict()){ |
+ *status = U_INVALID_FORMAT_ERROR; |
+ return NULL; |
+ } |
+ } |
+ |
+ cleanupLookahead(&state); |
+ ustr_deinit(&comment); |
+ return state.bundle; |
+} |
Property changes on: icu46/source/tools/genrb/parse.c |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |