2 *******************************************************************************
4 * Copyright (C) 1998-2006, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
11 * Modification History:
13 * Date Name Description
14 * 05/26/99 stephen Creation.
15 * 02/25/00 weiv Overhaul to write udata
16 * 5/10/01 Ram removed ustdio dependency
17 * 06/10/2001 Dominic Ludlam <dom@recoil.org> Rewritten
18 *******************************************************************************
32 #include "unicode/ustring.h"
33 #include "unicode/putil.h"
36 /* Number of tokens to read ahead of the current stream position */
37 #define MAX_LOOKAHEAD 3
47 #define STARTCOMMAND 0x005B
48 #define ENDCOMMAND 0x005D
49 #define OPENSQBRACKET 0x005B
50 #define CLOSESQBRACKET 0x005D
52 typedef struct SResource
*
53 ParseResourceFunction(char *tag
, uint32_t startline
, const struct UString
* comment
, UErrorCode
*status
);
59 struct UString comment
;
63 /* keep in sync with token defines in read.h */
64 const char *tokenNames
[TOK_TOKEN_COUNT
] =
66 "string", /* A string token, such as "MonthNames" */
67 "'{'", /* An opening brace character */
68 "'}'", /* A closing brace character */
72 "<end of file>", /* End of the file has been reached successfully */
76 /* Just to store "TRUE" */
77 static const UChar trueValue
[] = {0x0054, 0x0052, 0x0055, 0x0045, 0x0000};
79 static struct Lookahead lookahead
[MAX_LOOKAHEAD
+ 1];
80 static uint32_t lookaheadPosition
;
81 static UCHARBUF
*buffer
;
83 static struct SRBRoot
*bundle
;
84 static const char *inputdir
;
85 static uint32_t inputdirLength
;
86 static const char *outputdir
;
87 static uint32_t outputdirLength
;
89 static UBool gMakeBinaryCollation
= TRUE
;
91 static struct SResource
*parseResource(char *tag
, const struct UString
*comment
, UErrorCode
*status
);
93 /* The nature of the lookahead buffer:
94 There are MAX_LOOKAHEAD + 1 slots, used as a circular buffer. This provides
95 MAX_LOOKAHEAD lookahead tokens and a slot for the current token and value.
96 When getToken is called, the current pointer is moved to the next slot and the
97 old slot is filled with the next token from the reader by calling getNextToken.
98 The token values are stored in the slot, which means that token values don't
99 survive a call to getToken, ie.
103 getToken(&value, NULL, status);
104 getToken(NULL, NULL, status); bad - value is now a different string
107 initLookahead(UCHARBUF
*buf
, UErrorCode
*status
)
109 static uint32_t initTypeStrings
= 0;
112 if (!initTypeStrings
)
117 lookaheadPosition
= 0;
122 for (i
= 0; i
< MAX_LOOKAHEAD
; i
++)
124 lookahead
[i
].type
= getNextToken(buffer
, &lookahead
[i
].value
, &lookahead
[i
].line
, &lookahead
[i
].comment
, status
);
125 if (U_FAILURE(*status
))
131 *status
= U_ZERO_ERROR
;
134 static enum ETokenType
135 getToken(struct UString
**tokenValue
, struct UString
* comment
, uint32_t *linenumber
, UErrorCode
*status
)
137 enum ETokenType result
;
140 result
= lookahead
[lookaheadPosition
].type
;
142 if (tokenValue
!= NULL
)
144 *tokenValue
= &lookahead
[lookaheadPosition
].value
;
147 if (linenumber
!= NULL
)
149 *linenumber
= lookahead
[lookaheadPosition
].line
;
154 ustr_cpy(comment
, &(lookahead
[lookaheadPosition
].comment
), status
);
157 i
= (lookaheadPosition
+ MAX_LOOKAHEAD
) % (MAX_LOOKAHEAD
+ 1);
158 lookaheadPosition
= (lookaheadPosition
+ 1) % (MAX_LOOKAHEAD
+ 1);
159 ustr_setlen(&lookahead
[i
].comment
, 0, status
);
160 ustr_setlen(&lookahead
[i
].value
, 0, status
);
161 lookahead
[i
].type
= getNextToken(buffer
, &lookahead
[i
].value
, &lookahead
[i
].line
, &lookahead
[i
].comment
, status
);
163 /* printf("getToken, returning %s\n", tokenNames[result]); */
168 static enum ETokenType
169 peekToken(uint32_t lookaheadCount
, struct UString
**tokenValue
, uint32_t *linenumber
, struct UString
*comment
, UErrorCode
*status
)
171 uint32_t i
= (lookaheadPosition
+ lookaheadCount
) % (MAX_LOOKAHEAD
+ 1);
173 if (U_FAILURE(*status
))
178 if (lookaheadCount
>= MAX_LOOKAHEAD
)
180 *status
= U_INTERNAL_PROGRAM_ERROR
;
184 if (tokenValue
!= NULL
)
186 *tokenValue
= &lookahead
[i
].value
;
189 if (linenumber
!= NULL
)
191 *linenumber
= lookahead
[i
].line
;
195 ustr_cpy(comment
, &(lookahead
[lookaheadPosition
].comment
), status
);
198 return lookahead
[i
].type
;
202 expect(enum ETokenType expectedToken
, struct UString
**tokenValue
, struct UString
*comment
, uint32_t *linenumber
, UErrorCode
*status
)
206 enum ETokenType token
= getToken(tokenValue
, comment
, &line
, status
);
208 if (linenumber
!= NULL
)
213 if (U_FAILURE(*status
))
218 if (token
!= expectedToken
)
220 *status
= U_INVALID_FORMAT_ERROR
;
221 error(line
, "expecting %s, got %s", tokenNames
[expectedToken
], tokenNames
[token
]);
223 else /* "else" is added by Jing/GCL */
225 *status
= U_ZERO_ERROR
;
229 static char *getInvariantString(uint32_t *line
, struct UString
*comment
, UErrorCode
*status
)
231 struct UString
*tokenValue
;
235 expect(TOK_STRING
, &tokenValue
, comment
, line
, status
);
237 if (U_FAILURE(*status
))
242 count
= u_strlen(tokenValue
->fChars
);
243 if(!uprv_isInvariantUString(tokenValue
->fChars
, count
)) {
244 *status
= U_INVALID_FORMAT_ERROR
;
245 error(*line
, "invariant characters required for table keys, binary data, etc.");
249 result
= uprv_malloc(count
+1);
253 *status
= U_MEMORY_ALLOCATION_ERROR
;
257 u_UCharsToChars(tokenValue
->fChars
, result
, count
+1);
261 static struct SResource
*
262 parseUCARules(char *tag
, uint32_t startline
, const struct UString
* comment
, UErrorCode
*status
)
264 struct SResource
*result
= NULL
;
265 struct UString
*tokenValue
;
266 FileStream
*file
= NULL
;
267 char filename
[256] = { '\0' };
268 char cs
[128] = { '\0' };
271 UBool quoted
= FALSE
;
272 UCHARBUF
*ucbuf
=NULL
;
274 const char* cp
= NULL
;
275 UChar
*pTarget
= NULL
;
276 UChar
*target
= NULL
;
277 UChar
*targetLimit
= NULL
;
280 expect(TOK_STRING
, &tokenValue
, NULL
, &line
, status
);
283 printf(" %s at line %i \n", (tag
== NULL
) ? "(null)" : tag
, (int)startline
);
286 if (U_FAILURE(*status
))
290 /* make the filename including the directory */
291 if (inputdir
!= NULL
)
293 uprv_strcat(filename
, inputdir
);
295 if (inputdir
[inputdirLength
- 1] != U_FILE_SEP_CHAR
)
297 uprv_strcat(filename
, U_FILE_SEP_STRING
);
301 u_UCharsToChars(tokenValue
->fChars
, cs
, tokenValue
->fLength
);
303 expect(TOK_CLOSE_BRACE
, NULL
, NULL
, NULL
, status
);
305 if (U_FAILURE(*status
))
309 uprv_strcat(filename
, cs
);
312 ucbuf
= ucbuf_open(filename
, &cp
, getShowWarning(),FALSE
, status
);
314 if (U_FAILURE(*status
)) {
315 error(line
, "An error occured while opening the input file %s\n", filename
);
319 /* We allocate more space than actually required
320 * since the actual size needed for storing UChars
321 * is not known in UTF-8 byte stream
323 size
= ucbuf_size(ucbuf
) + 1;
324 pTarget
= (UChar
*) uprv_malloc(U_SIZEOF_UCHAR
* size
);
325 uprv_memset(pTarget
, 0, size
*U_SIZEOF_UCHAR
);
327 targetLimit
= pTarget
+size
;
329 /* read the rules into the buffer */
330 while (target
< targetLimit
)
332 c
= ucbuf_getc(ucbuf
, status
);
334 quoted
= (UBool
)!quoted
;
336 /* weiv (06/26/2002): adding the following:
337 * - preserving spaces in commands [...]
338 * - # comments until the end of line
340 if (c
== STARTCOMMAND
&& !quoted
)
343 * closing bracket will be handled by the
344 * append at the end of the loop
346 while(c
!= ENDCOMMAND
) {
347 U_APPEND_CHAR32(c
, target
,len
);
348 c
= ucbuf_getc(ucbuf
, status
);
351 else if (c
== HASH
&& !quoted
) {
353 while(c
!= CR
&& c
!= LF
) {
354 c
= ucbuf_getc(ucbuf
, status
);
358 else if (c
== ESCAPE
)
360 c
= unescape(ucbuf
, status
);
365 T_FileStream_close(file
);
369 else if (!quoted
&& (c
== SPACE
|| c
== TAB
|| c
== CR
|| c
== LF
))
371 /* ignore spaces carriage returns
372 * and line feed unless in the form \uXXXX
377 /* Append UChar * after dissembling if c > 0xffff*/
380 U_APPEND_CHAR32(c
, target
,len
);
388 /* terminate the string */
389 if(target
< targetLimit
){
393 result
= string_open(bundle
, tag
, pTarget
, (int32_t)(target
- pTarget
), NULL
, status
);
398 T_FileStream_close(file
);
403 static struct SResource
*
404 parseTransliterator(char *tag
, uint32_t startline
, const struct UString
* comment
, UErrorCode
*status
)
406 struct SResource
*result
= NULL
;
407 struct UString
*tokenValue
;
408 FileStream
*file
= NULL
;
409 char filename
[256] = { '\0' };
410 char cs
[128] = { '\0' };
412 UCHARBUF
*ucbuf
=NULL
;
413 const char* cp
= NULL
;
414 UChar
*pTarget
= NULL
;
415 const UChar
*pSource
= NULL
;
418 expect(TOK_STRING
, &tokenValue
, NULL
, &line
, status
);
421 printf(" %s at line %i \n", (tag
== NULL
) ? "(null)" : tag
, (int)startline
);
424 if (U_FAILURE(*status
))
428 /* make the filename including the directory */
429 if (inputdir
!= NULL
)
431 uprv_strcat(filename
, inputdir
);
433 if (inputdir
[inputdirLength
- 1] != U_FILE_SEP_CHAR
)
435 uprv_strcat(filename
, U_FILE_SEP_STRING
);
439 u_UCharsToChars(tokenValue
->fChars
, cs
, tokenValue
->fLength
);
441 expect(TOK_CLOSE_BRACE
, NULL
, NULL
, NULL
, status
);
443 if (U_FAILURE(*status
))
447 uprv_strcat(filename
, cs
);
450 ucbuf
= ucbuf_open(filename
, &cp
, getShowWarning(),FALSE
, status
);
452 if (U_FAILURE(*status
)) {
453 error(line
, "An error occured while opening the input file %s\n", filename
);
457 /* We allocate more space than actually required
458 * since the actual size needed for storing UChars
459 * is not known in UTF-8 byte stream
461 pSource
= ucbuf_getBuffer(ucbuf
, &size
, status
);
462 pTarget
= (UChar
*) uprv_malloc(U_SIZEOF_UCHAR
* (size
+ 1));
463 uprv_memset(pTarget
, 0, size
*U_SIZEOF_UCHAR
);
465 #if !UCONFIG_NO_TRANSLITERATION
466 size
= utrans_stripRules(pSource
, size
, pTarget
, status
);
469 fprintf(stderr
, " Warning: writing empty transliteration data ( UCONFIG_NO_TRANSLITERATION ) \n");
471 result
= string_open(bundle
, tag
, pTarget
, size
, NULL
, status
);
475 T_FileStream_close(file
);
479 static struct SResource
* dependencyArray
= NULL
;
481 static struct SResource
*
482 parseDependency(char *tag
, uint32_t startline
, const struct UString
* comment
, UErrorCode
*status
)
484 struct SResource
*result
= NULL
;
485 struct SResource
*elem
= NULL
;
486 struct UString
*tokenValue
;
488 char filename
[256] = { '\0' };
489 char cs
[128] = { '\0' };
491 expect(TOK_STRING
, &tokenValue
, NULL
, &line
, status
);
494 printf(" %s at line %i \n", (tag
== NULL
) ? "(null)" : tag
, (int)startline
);
497 if (U_FAILURE(*status
))
501 /* make the filename including the directory */
502 if (outputdir
!= NULL
)
504 uprv_strcat(filename
, outputdir
);
506 if (outputdir
[outputdirLength
- 1] != U_FILE_SEP_CHAR
)
508 uprv_strcat(filename
, U_FILE_SEP_STRING
);
512 u_UCharsToChars(tokenValue
->fChars
, cs
, tokenValue
->fLength
);
514 if (U_FAILURE(*status
))
518 uprv_strcat(filename
, cs
);
519 if(!T_FileStream_file_exists(filename
)){
521 error(line
, "The dependency file %s does not exist. Please make sure it exists.\n",filename
);
523 warning(line
, "The dependency file %s does not exist. Please make sure it exists.\n",filename
);
526 if(dependencyArray
==NULL
){
527 dependencyArray
= array_open(bundle
, "%%DEPENDENCY", NULL
, status
);
530 result
= string_open(bundle
, tag
, tokenValue
->fChars
, tokenValue
->fLength
, comment
, status
);
532 elem
= string_open(bundle
, NULL
, tokenValue
->fChars
, tokenValue
->fLength
, comment
, status
);
534 array_add(dependencyArray
, elem
, status
);
536 if (U_FAILURE(*status
))
540 expect(TOK_CLOSE_BRACE
, NULL
, NULL
, NULL
, status
);
543 static struct SResource
*
544 parseString(char *tag
, uint32_t startline
, const struct UString
* comment
, UErrorCode
*status
)
546 struct UString
*tokenValue
;
547 struct SResource
*result
= NULL
;
549 /* if (tag != NULL && uprv_strcmp(tag, "%%UCARULES") == 0)
551 return parseUCARules(tag, startline, status);
554 printf(" string %s at line %i \n", (tag
== NULL
) ? "(null)" : tag
, (int)startline
);
556 expect(TOK_STRING
, &tokenValue
, NULL
, NULL
, status
);
558 if (U_SUCCESS(*status
))
560 /* create the string now - tokenValue doesn't survive a call to getToken (and therefore
561 doesn't survive expect either) */
563 result
= string_open(bundle
, tag
, tokenValue
->fChars
, tokenValue
->fLength
, comment
, status
);
564 if(U_SUCCESS(*status
) && result
) {
565 expect(TOK_CLOSE_BRACE
, NULL
, NULL
, NULL
, status
);
567 if (U_FAILURE(*status
))
569 string_close(result
, status
);
578 static struct SResource
*
579 parseAlias(char *tag
, uint32_t startline
, const struct UString
*comment
, UErrorCode
*status
)
581 struct UString
*tokenValue
;
582 struct SResource
*result
= NULL
;
584 expect(TOK_STRING
, &tokenValue
, NULL
, NULL
, status
);
587 printf(" alias %s at line %i \n", (tag
== NULL
) ? "(null)" : tag
, (int)startline
);
590 if (U_SUCCESS(*status
))
592 /* create the string now - tokenValue doesn't survive a call to getToken (and therefore
593 doesn't survive expect either) */
595 result
= alias_open(bundle
, tag
, tokenValue
->fChars
, tokenValue
->fLength
, comment
, status
);
597 expect(TOK_CLOSE_BRACE
, NULL
, NULL
, NULL
, status
);
599 if (U_FAILURE(*status
))
601 alias_close(result
, status
);
609 static struct SResource
*
610 addCollation(struct SResource
*result
, uint32_t startline
, UErrorCode
*status
)
612 struct SResource
*member
= NULL
;
613 struct UString
*tokenValue
;
614 struct UString comment
;
615 enum ETokenType token
;
617 UVersionInfo version
;
618 UBool override
= FALSE
;
620 /* '{' . (name resource)* '}' */
621 version
[0]=0; version
[1]=0; version
[2]=0; version
[3]=0;
626 token
= getToken(&tokenValue
, &comment
, &line
, status
);
628 if (token
== TOK_CLOSE_BRACE
)
633 if (token
!= TOK_STRING
)
635 table_close(result
, status
);
636 *status
= U_INVALID_FORMAT_ERROR
;
638 if (token
== TOK_EOF
)
640 error(startline
, "unterminated table");
644 error(line
, "Unexpected token %s", tokenNames
[token
]);
650 u_UCharsToChars(tokenValue
->fChars
, subtag
, u_strlen(tokenValue
->fChars
) + 1);
652 if (U_FAILURE(*status
))
654 table_close(result
, status
);
658 member
= parseResource(subtag
, NULL
, status
);
660 if (U_FAILURE(*status
))
662 table_close(result
, status
);
666 if (uprv_strcmp(subtag
, "Version") == 0)
669 int32_t length
= member
->u
.fString
.fLength
;
671 if (length
>= (int32_t) sizeof(ver
))
673 length
= (int32_t) sizeof(ver
) - 1;
676 u_UCharsToChars(member
->u
.fString
.fChars
, ver
, length
+ 1); /* +1 for copying NULL */
677 u_versionFromString(version
, ver
);
679 table_add(result
, member
, line
, status
);
682 else if (uprv_strcmp(subtag
, "Override") == 0)
686 if (u_strncmp(member
->u
.fString
.fChars
, trueValue
, u_strlen(trueValue
)) == 0)
690 table_add(result
, member
, line
, status
);
693 else if(uprv_strcmp(subtag
, "%%CollationBin")==0)
695 /* discard duplicate %%CollationBin if any*/
697 else if (uprv_strcmp(subtag
, "Sequence") == 0)
699 #if UCONFIG_NO_COLLATION
700 warning(line
, "Not building collation elements because of UCONFIG_NO_COLLATION, see uconfig.h");
702 /* first we add the "Sequence", so that we always have rules */
703 table_add(result
, member
, line
, status
);
704 if(gMakeBinaryCollation
) {
705 UErrorCode intStatus
= U_ZERO_ERROR
;
707 /* do the collation elements */
709 uint8_t *data
= NULL
;
710 UCollator
*coll
= NULL
;
711 UParseError parseError
;
713 /*table_add(result, member, line, status);*/
715 coll
= ucol_openRules(member
->u
.fString
.fChars
, member
->u
.fString
.fLength
,
716 UCOL_OFF
, UCOL_DEFAULT_STRENGTH
,&parseError
, &intStatus
);
718 if (U_SUCCESS(intStatus
) && coll
!= NULL
)
720 len
= ucol_cloneBinary(coll
, NULL
, 0, &intStatus
);
721 data
= (uint8_t *)uprv_malloc(len
);
722 intStatus
= U_ZERO_ERROR
;
723 len
= ucol_cloneBinary(coll
, data
, len
, &intStatus
);
724 /*data = ucol_cloneRuleData(coll, &len, &intStatus);*/
726 /* tailoring rules version */
728 /*coll->dataInfo.dataVersion[1] = version[0];*/
729 /* Copy tailoring version. Builder version already */
730 /* set in ucol_openRules */
731 ((UCATableHeader
*)data
)->version
[1] = version
[0];
732 ((UCATableHeader
*)data
)->version
[2] = version
[1];
733 ((UCATableHeader
*)data
)->version
[3] = version
[2];
735 if (U_SUCCESS(intStatus
) && data
!= NULL
)
737 member
= bin_open(bundle
, "%%CollationBin", len
, data
, NULL
, NULL
, status
);
738 /*table_add(bundle->fRoot, member, line, status);*/
739 table_add(result
, member
, line
, status
);
744 warning(line
, "could not obtain rules from collator");
746 *status
= U_INVALID_FORMAT_ERROR
;
755 warning(line
, "%%Collation could not be constructed from CollationElements - check context!");
763 printf("Not building Collation binary\n");
769 /*member = string_open(bundle, subtag, tokenValue->fChars, tokenValue->fLength, status);*/
771 /*expect(TOK_CLOSE_BRACE, NULL, NULL, status);*/
773 if (U_FAILURE(*status
))
775 table_close(result
, status
);
781 /* A compiler warning will appear if all paths don't contain a return statement. */
782 /* *status = U_INTERNAL_PROGRAM_ERROR;
786 static struct SResource
*
787 parseCollationElements(char *tag
, uint32_t startline
, UBool newCollation
, UErrorCode
*status
)
789 struct SResource
*result
= NULL
;
790 struct SResource
*member
= NULL
;
791 struct SResource
*collationRes
= NULL
;
792 struct UString
*tokenValue
;
793 struct UString comment
;
794 enum ETokenType token
;
795 char subtag
[1024], typeKeyword
[1024];
798 result
= table_open(bundle
, tag
, NULL
, status
);
800 if (result
== NULL
|| U_FAILURE(*status
))
805 printf(" collation elements %s at line %i \n", (tag
== NULL
) ? "(null)" : tag
, (int)startline
);
808 return addCollation(result
, startline
, status
);
813 token
= getToken(&tokenValue
, &comment
, &line
, status
);
815 if (token
== TOK_CLOSE_BRACE
)
820 if (token
!= TOK_STRING
)
822 table_close(result
, status
);
823 *status
= U_INVALID_FORMAT_ERROR
;
825 if (token
== TOK_EOF
)
827 error(startline
, "unterminated table");
831 error(line
, "Unexpected token %s", tokenNames
[token
]);
837 u_UCharsToChars(tokenValue
->fChars
, subtag
, u_strlen(tokenValue
->fChars
) + 1);
839 if (U_FAILURE(*status
))
841 table_close(result
, status
);
845 if (uprv_strcmp(subtag
, "default") == 0)
847 member
= parseResource(subtag
, NULL
, status
);
849 if (U_FAILURE(*status
))
851 table_close(result
, status
);
855 table_add(result
, member
, line
, status
);
859 token
= peekToken(0, &tokenValue
, &line
, &comment
, status
);
860 /* this probably needs to be refactored or recursively use the parser */
861 /* first we assume that our collation table won't have the explicit type */
862 /* then, we cannot handle aliases */
863 if(token
== TOK_OPEN_BRACE
) {
864 token
= getToken(&tokenValue
, &comment
, &line
, status
);
865 collationRes
= table_open(bundle
, subtag
, NULL
, status
);
866 table_add(result
, addCollation(collationRes
, startline
, status
), startline
, status
);
867 } else if(token
== TOK_COLON
) { /* right now, we'll just try to see if we have aliases */
868 /* we could have a table too */
869 token
= peekToken(1, &tokenValue
, &line
, &comment
, status
);
870 u_UCharsToChars(tokenValue
->fChars
, typeKeyword
, u_strlen(tokenValue
->fChars
) + 1);
871 if(uprv_strcmp(typeKeyword
, "alias") == 0) {
872 member
= parseResource(subtag
, NULL
, status
);
874 if (U_FAILURE(*status
))
876 table_close(result
, status
);
880 table_add(result
, member
, line
, status
);
882 *status
= U_INVALID_FORMAT_ERROR
;
886 *status
= U_INVALID_FORMAT_ERROR
;
891 /*member = string_open(bundle, subtag, tokenValue->fChars, tokenValue->fLength, status);*/
893 /*expect(TOK_CLOSE_BRACE, NULL, NULL, status);*/
895 if (U_FAILURE(*status
))
897 table_close(result
, status
);
904 /* Necessary, because CollationElements requires the bundle->fRoot member to be present which,
905 if this weren't special-cased, wouldn't be set until the entire file had been processed. */
906 static struct SResource
*
907 realParseTable(struct SResource
*table
, char *tag
, uint32_t startline
, UErrorCode
*status
)
909 struct SResource
*member
= NULL
;
910 struct UString
*tokenValue
=NULL
;
911 struct UString comment
;
912 enum ETokenType token
;
915 UBool readToken
= FALSE
;
917 /* '{' . (name resource)* '}' */
919 printf(" parsing table %s at line %i \n", (tag
== NULL
) ? "(null)" : tag
, (int)startline
);
924 token
= getToken(&tokenValue
, &comment
, &line
, status
);
926 if (token
== TOK_CLOSE_BRACE
)
929 warning(startline
, "Encountered empty table");
934 if (token
!= TOK_STRING
)
936 table_close(table
, status
);
937 *status
= U_INVALID_FORMAT_ERROR
;
939 if (token
== TOK_EOF
)
941 error(startline
, "unterminated table");
945 error(line
, "unexpected token %s", tokenNames
[token
]);
951 if(uprv_isInvariantUString(tokenValue
->fChars
, -1)) {
952 u_UCharsToChars(tokenValue
->fChars
, subtag
, u_strlen(tokenValue
->fChars
) + 1);
954 *status
= U_INVALID_FORMAT_ERROR
;
955 error(line
, "invariant characters required for table keys");
956 table_close(table
, status
);
960 if (U_FAILURE(*status
))
962 error(line
, "parse error. Stopped parsing with %s", u_errorName(*status
));
963 table_close(table
, status
);
967 member
= parseResource(subtag
, &comment
, status
);
969 if (member
== NULL
|| U_FAILURE(*status
))
971 error(line
, "parse error. Stopped parsing with %s", u_errorName(*status
));
972 table_close(table
, status
);
976 table_add(table
, member
, line
, status
);
978 if (U_FAILURE(*status
))
980 error(line
, "parse error. Stopped parsing with %s", u_errorName(*status
));
981 table_close(table
, status
);
988 /* A compiler warning will appear if all paths don't contain a return statement. */
989 /* *status = U_INTERNAL_PROGRAM_ERROR;
993 static struct SResource
*
994 parseTable(char *tag
, uint32_t startline
, const struct UString
*comment
, UErrorCode
*status
)
996 struct SResource
*result
;
998 if (tag
!= NULL
&& uprv_strcmp(tag
, "CollationElements") == 0)
1000 return parseCollationElements(tag
, startline
, FALSE
, status
);
1002 if (tag
!= NULL
&& uprv_strcmp(tag
, "collations") == 0)
1004 return parseCollationElements(tag
, startline
, TRUE
, status
);
1007 printf(" table %s at line %i \n", (tag
== NULL
) ? "(null)" : tag
, (int)startline
);
1010 result
= table_open(bundle
, tag
, comment
, status
);
1012 if (result
== NULL
|| U_FAILURE(*status
))
1017 return realParseTable(result
, tag
, startline
, status
);
1020 static struct SResource
*
1021 parseArray(char *tag
, uint32_t startline
, const struct UString
*comment
, UErrorCode
*status
)
1023 struct SResource
*result
= NULL
;
1024 struct SResource
*member
= NULL
;
1025 struct UString
*tokenValue
;
1026 struct UString memberComments
;
1027 enum ETokenType token
;
1028 UBool readToken
= FALSE
;
1030 result
= array_open(bundle
, tag
, comment
, status
);
1032 if (result
== NULL
|| U_FAILURE(*status
))
1037 printf(" array %s at line %i \n", (tag
== NULL
) ? "(null)" : tag
, (int)startline
);
1040 ustr_init(&memberComments
);
1042 /* '{' . resource [','] '}' */
1046 ustr_setlen(&memberComments
, 0, status
);
1048 /* check for end of array, but don't consume next token unless it really is the end */
1049 token
= peekToken(0, &tokenValue
, NULL
, &memberComments
, status
);
1052 if (token
== TOK_CLOSE_BRACE
)
1054 getToken(NULL
, NULL
, NULL
, status
);
1056 warning(startline
, "Encountered empty array");
1061 if (token
== TOK_EOF
)
1063 array_close(result
, status
);
1064 *status
= U_INVALID_FORMAT_ERROR
;
1065 error(startline
, "unterminated array");
1069 /* string arrays are a special case */
1070 if (token
== TOK_STRING
)
1072 getToken(&tokenValue
, &memberComments
, NULL
, status
);
1073 member
= string_open(bundle
, NULL
, tokenValue
->fChars
, tokenValue
->fLength
, &memberComments
, status
);
1077 member
= parseResource(NULL
, &memberComments
, status
);
1080 if (member
== NULL
|| U_FAILURE(*status
))
1082 array_close(result
, status
);
1086 array_add(result
, member
, status
);
1088 if (U_FAILURE(*status
))
1090 array_close(result
, status
);
1094 /* eat optional comma if present */
1095 token
= peekToken(0, NULL
, NULL
, NULL
, status
);
1097 if (token
== TOK_COMMA
)
1099 getToken(NULL
, NULL
, NULL
, status
);
1102 if (U_FAILURE(*status
))
1104 array_close(result
, status
);
1113 static struct SResource
*
1114 parseIntVector(char *tag
, uint32_t startline
, const struct UString
*comment
, UErrorCode
*status
)
1116 struct SResource
*result
= NULL
;
1117 enum ETokenType token
;
1120 UBool readToken
= FALSE
;
1121 /* added by Jing/GCL */
1124 struct UString memberComments
;
1126 result
= intvector_open(bundle
, tag
, comment
, status
);
1128 if (result
== NULL
|| U_FAILURE(*status
))
1134 printf(" vector %s at line %i \n", (tag
== NULL
) ? "(null)" : tag
, (int)startline
);
1136 ustr_init(&memberComments
);
1137 /* '{' . string [','] '}' */
1140 ustr_setlen(&memberComments
, 0, status
);
1142 /* check for end of array, but don't consume next token unless it really is the end */
1143 token
= peekToken(0, NULL
, NULL
,&memberComments
, status
);
1145 if (token
== TOK_CLOSE_BRACE
)
1147 /* it's the end, consume the close brace */
1148 getToken(NULL
, NULL
, NULL
, status
);
1150 warning(startline
, "Encountered empty int vector");
1155 string
= getInvariantString(NULL
, NULL
, status
);
1157 if (U_FAILURE(*status
))
1159 intvector_close(result
, status
);
1162 /* Commented by Jing/GCL */
1163 /*value = uprv_strtol(string, NULL, 10);
1164 intvector_add(result, value, status);
1168 token = peekToken(0, NULL, NULL, status);*/
1170 /* The following is added by Jing/GCL to handle illegal char in the Intvector */
1171 value
= uprv_strtoul(string
, &stopstring
, 0);/* make intvector support decimal,hexdigit,octal digit ranging from -2^31-2^32-1*/
1172 len
=(uint32_t)(stopstring
-string
);
1174 if(len
==uprv_strlen(string
))
1176 intvector_add(result
, value
, status
);
1178 token
= peekToken(0, NULL
, NULL
, NULL
, status
);
1183 *status
=U_INVALID_CHAR_FOUND
;
1185 /* The above is added by Jing/GCL */
1187 if (U_FAILURE(*status
))
1189 intvector_close(result
, status
);
1193 /* the comma is optional (even though it is required to prevent the reader from concatenating
1194 consecutive entries) so that a missing comma on the last entry isn't an error */
1195 if (token
== TOK_COMMA
)
1197 getToken(NULL
, NULL
, NULL
, status
);
1203 /* A compiler warning will appear if all paths don't contain a return statement. */
1204 /* intvector_close(result, status);
1205 *status = U_INTERNAL_PROGRAM_ERROR;
1209 static struct SResource
*
1210 parseBinary(char *tag
, uint32_t startline
, const struct UString
*comment
, UErrorCode
*status
)
1212 struct SResource
*result
= NULL
;
1215 char toConv
[3] = {'\0', '\0', '\0'};
1219 /* added by Jing/GCL */
1223 string
= getInvariantString(&line
, NULL
, status
);
1225 if (string
== NULL
|| U_FAILURE(*status
))
1230 expect(TOK_CLOSE_BRACE
, NULL
, NULL
, NULL
, status
);
1232 if (U_FAILURE(*status
))
1239 printf(" binary %s at line %i \n", (tag
== NULL
) ? "(null)" : tag
, (int)startline
);
1242 count
= (uint32_t)uprv_strlen(string
);
1245 value
= uprv_malloc(sizeof(uint8_t) * count
);
1250 *status
= U_MEMORY_ALLOCATION_ERROR
;
1254 for (i
= 0; i
< count
; i
+= 2)
1256 toConv
[0] = string
[i
];
1257 toConv
[1] = string
[i
+ 1];
1259 value
[i
>> 1] = (uint8_t) uprv_strtoul(toConv
, &stopstring
, 16);
1260 len
=(uint32_t)(stopstring
-toConv
);
1262 if(len
!=uprv_strlen(toConv
))
1265 *status
=U_INVALID_CHAR_FOUND
;
1270 result
= bin_open(bundle
, tag
, (i
>> 1), value
,NULL
, comment
, status
);
1276 *status
= U_INVALID_CHAR_FOUND
;
1278 error(line
, "Encountered invalid binary string");
1284 result
= bin_open(bundle
, tag
, 0, NULL
, "",comment
,status
);
1285 warning(startline
, "Encountered empty binary tag");
1292 static struct SResource
*
1293 parseInteger(char *tag
, uint32_t startline
, const struct UString
*comment
, UErrorCode
*status
)
1295 struct SResource
*result
= NULL
;
1298 /* added by Jing/GCL */
1302 string
= getInvariantString(NULL
, NULL
, status
);
1304 if (string
== NULL
|| U_FAILURE(*status
))
1309 expect(TOK_CLOSE_BRACE
, NULL
, NULL
, NULL
, status
);
1311 if (U_FAILURE(*status
))
1318 printf(" integer %s at line %i \n", (tag
== NULL
) ? "(null)" : tag
, (int)startline
);
1321 if (uprv_strlen(string
) <= 0)
1323 warning(startline
, "Encountered empty integer. Default value is 0.");
1326 /* commented by Jing/GCL */
1327 /* value = uprv_strtol(string, NULL, 10);*/
1328 /* result = int_open(bundle, tag, value, status);*/
1329 /* The following is added by Jing/GCL*/
1330 /* to make integer support hexdecimal, octal digit and decimal*/
1331 /* to handle illegal char in the integer*/
1332 value
= uprv_strtoul(string
, &stopstring
, 0);
1333 len
=(uint32_t)(stopstring
-string
);
1334 if(len
==uprv_strlen(string
))
1336 result
= int_open(bundle
, tag
, value
, comment
, status
);
1340 *status
=U_INVALID_CHAR_FOUND
;
1347 static struct SResource
*
1348 parseImport(char *tag
, uint32_t startline
, const struct UString
* comment
, UErrorCode
*status
)
1350 struct SResource
*result
;
1356 char *fullname
= NULL
;
1357 int32_t numRead
= 0;
1358 filename
= getInvariantString(&line
, NULL
, status
);
1360 if (U_FAILURE(*status
))
1365 expect(TOK_CLOSE_BRACE
, NULL
, NULL
, NULL
, status
);
1367 if (U_FAILURE(*status
))
1369 uprv_free(filename
);
1374 printf(" import %s at line %i \n", (tag
== NULL
) ? "(null)" : tag
, (int)startline
);
1377 /* Open the input file for reading */
1378 if (inputdir
== NULL
)
1380 file
= T_FileStream_open(filename
, "rb");
1385 int32_t count
= (int32_t)uprv_strlen(filename
);
1387 if (inputdir
[inputdirLength
- 1] != U_FILE_SEP_CHAR
)
1389 fullname
= (char *) uprv_malloc(inputdirLength
+ count
+ 2);
1392 if(fullname
== NULL
)
1394 *status
= U_MEMORY_ALLOCATION_ERROR
;
1398 uprv_strcpy(fullname
, inputdir
);
1400 fullname
[inputdirLength
] = U_FILE_SEP_CHAR
;
1401 fullname
[inputdirLength
+ 1] = '\0';
1403 uprv_strcat(fullname
, filename
);
1407 fullname
= (char *) uprv_malloc(inputdirLength
+ count
+ 1);
1410 if(fullname
== NULL
)
1412 *status
= U_MEMORY_ALLOCATION_ERROR
;
1416 uprv_strcpy(fullname
, inputdir
);
1417 uprv_strcat(fullname
, filename
);
1420 file
= T_FileStream_open(fullname
, "rb");
1426 error(line
, "couldn't open input file %s", filename
);
1427 *status
= U_FILE_ACCESS_ERROR
;
1431 len
= T_FileStream_size(file
);
1432 data
= (uint8_t*)uprv_malloc(len
* sizeof(uint8_t));
1436 *status
= U_MEMORY_ALLOCATION_ERROR
;
1437 T_FileStream_close (file
);
1441 numRead
= T_FileStream_read (file
, data
, len
);
1442 T_FileStream_close (file
);
1444 result
= bin_open(bundle
, tag
, len
, data
, fullname
, comment
, status
);
1447 uprv_free(filename
);
1448 uprv_free(fullname
);
1453 static struct SResource
*
1454 parseInclude(char *tag
, uint32_t startline
, const struct UString
* comment
, UErrorCode
*status
)
1456 struct SResource
*result
;
1460 UChar
*pTarget
= NULL
;
1463 char *fullname
= NULL
;
1465 const char* cp
= NULL
;
1466 const UChar
* uBuffer
= NULL
;
1468 filename
= getInvariantString(&line
, NULL
, status
);
1469 count
= (int32_t)uprv_strlen(filename
);
1471 if (U_FAILURE(*status
))
1476 expect(TOK_CLOSE_BRACE
, NULL
, NULL
, NULL
, status
);
1478 if (U_FAILURE(*status
))
1480 uprv_free(filename
);
1485 printf(" include %s at line %i \n", (tag
== NULL
) ? "(null)" : tag
, (int)startline
);
1488 fullname
= (char *) uprv_malloc(inputdirLength
+ count
+ 2);
1490 if(fullname
== NULL
)
1492 *status
= U_MEMORY_ALLOCATION_ERROR
;
1493 uprv_free(filename
);
1498 if (inputdir
[inputdirLength
- 1] != U_FILE_SEP_CHAR
)
1501 uprv_strcpy(fullname
, inputdir
);
1503 fullname
[inputdirLength
] = U_FILE_SEP_CHAR
;
1504 fullname
[inputdirLength
+ 1] = '\0';
1506 uprv_strcat(fullname
, filename
);
1510 uprv_strcpy(fullname
, inputdir
);
1511 uprv_strcat(fullname
, filename
);
1514 uprv_strcpy(fullname
,filename
);
1517 ucbuf
= ucbuf_open(fullname
, &cp
,getShowWarning(),FALSE
,status
);
1519 if (U_FAILURE(*status
)) {
1520 error(line
, "couldn't open input file %s\n", filename
);
1524 uBuffer
= ucbuf_getBuffer(ucbuf
,&len
,status
);
1525 result
= string_open(bundle
, tag
, uBuffer
, len
, comment
, status
);
1529 uprv_free(filename
);
1530 uprv_free(fullname
);
1539 U_STRING_DECL(k_type_string
, "string", 6);
1540 U_STRING_DECL(k_type_binary
, "binary", 6);
1541 U_STRING_DECL(k_type_bin
, "bin", 3);
1542 U_STRING_DECL(k_type_table
, "table", 5);
1543 U_STRING_DECL(k_type_table_no_fallback
, "table(nofallback)", 17);
1544 U_STRING_DECL(k_type_int
, "int", 3);
1545 U_STRING_DECL(k_type_integer
, "integer", 7);
1546 U_STRING_DECL(k_type_array
, "array", 5);
1547 U_STRING_DECL(k_type_alias
, "alias", 5);
1548 U_STRING_DECL(k_type_intvector
, "intvector", 9);
1549 U_STRING_DECL(k_type_import
, "import", 6);
1550 U_STRING_DECL(k_type_include
, "include", 7);
1551 U_STRING_DECL(k_type_reserved
, "reserved", 8);
1553 /* Various non-standard processing plugins that create one or more special resources. */
1554 U_STRING_DECL(k_type_plugin_uca_rules
, "process(uca_rules)", 18);
1555 U_STRING_DECL(k_type_plugin_collation
, "process(collation)", 18);
1556 U_STRING_DECL(k_type_plugin_transliterator
, "process(transliterator)", 23);
1557 U_STRING_DECL(k_type_plugin_dependency
, "process(dependency)", 19);
1559 typedef enum EResourceType
1565 RT_TABLE_NO_FALLBACK
,
1572 RT_PROCESS_UCA_RULES
,
1573 RT_PROCESS_COLLATION
,
1574 RT_PROCESS_TRANSLITERATOR
,
1575 RT_PROCESS_DEPENDENCY
,
1580 const char *nameChars
; /* only used for debugging */
1581 const UChar
*nameUChars
;
1582 ParseResourceFunction
*parseFunction
;
1583 } gResourceTypes
[] = {
1584 {"Unknown", NULL
, NULL
},
1585 {"string", k_type_string
, parseString
},
1586 {"binary", k_type_binary
, parseBinary
},
1587 {"table", k_type_table
, parseTable
},
1588 {"table(nofallback)", k_type_table_no_fallback
, NULL
}, /* parseFunction will never be called */
1589 {"integer", k_type_integer
, parseInteger
},
1590 {"array", k_type_array
, parseArray
},
1591 {"alias", k_type_alias
, parseAlias
},
1592 {"intvector", k_type_intvector
, parseIntVector
},
1593 {"import", k_type_import
, parseImport
},
1594 {"include", k_type_include
, parseInclude
},
1595 {"process(uca_rules)", k_type_plugin_uca_rules
, parseUCARules
},
1596 {"process(collation)", k_type_plugin_collation
, NULL
/* not implemented yet */},
1597 {"process(transliterator)", k_type_plugin_transliterator
, parseTransliterator
},
1598 {"process(dependency)", k_type_plugin_dependency
, parseDependency
},
1599 {"reserved", NULL
, NULL
}
1602 void initParser(UBool makeBinaryCollation
)
1606 U_STRING_INIT(k_type_string
, "string", 6);
1607 U_STRING_INIT(k_type_binary
, "binary", 6);
1608 U_STRING_INIT(k_type_bin
, "bin", 3);
1609 U_STRING_INIT(k_type_table
, "table", 5);
1610 U_STRING_INIT(k_type_table_no_fallback
, "table(nofallback)", 17);
1611 U_STRING_INIT(k_type_int
, "int", 3);
1612 U_STRING_INIT(k_type_integer
, "integer", 7);
1613 U_STRING_INIT(k_type_array
, "array", 5);
1614 U_STRING_INIT(k_type_alias
, "alias", 5);
1615 U_STRING_INIT(k_type_intvector
, "intvector", 9);
1616 U_STRING_INIT(k_type_import
, "import", 6);
1617 U_STRING_INIT(k_type_reserved
, "reserved", 8);
1618 U_STRING_INIT(k_type_include
, "include", 7);
1620 U_STRING_INIT(k_type_plugin_uca_rules
, "process(uca_rules)", 18);
1621 U_STRING_INIT(k_type_plugin_collation
, "process(collation)", 18);
1622 U_STRING_INIT(k_type_plugin_transliterator
, "process(transliterator)", 23);
1623 U_STRING_INIT(k_type_plugin_dependency
, "process(dependency)", 19);
1625 for (i
= 0; i
< MAX_LOOKAHEAD
+ 1; i
++)
1627 ustr_init(&lookahead
[i
].value
);
1629 gMakeBinaryCollation
= makeBinaryCollation
;
1632 static U_INLINE UBool
isTable(enum EResourceType type
) {
1633 return (UBool
)(type
==RT_TABLE
|| type
==RT_TABLE_NO_FALLBACK
);
1636 static enum EResourceType
1637 parseResourceType(UErrorCode
*status
)
1639 struct UString
*tokenValue
;
1640 struct UString comment
;
1641 enum EResourceType result
= RT_UNKNOWN
;
1643 ustr_init(&comment
);
1644 expect(TOK_STRING
, &tokenValue
, &comment
, &line
, status
);
1646 if (U_FAILURE(*status
))
1651 *status
= U_ZERO_ERROR
;
1653 /* Search for normal types */
1655 while (++result
< RT_RESERVED
) {
1656 if (u_strcmp(tokenValue
->fChars
, gResourceTypes
[result
].nameUChars
) == 0) {
1660 /* Now search for the aliases */
1661 if (u_strcmp(tokenValue
->fChars
, k_type_int
) == 0) {
1662 result
= RT_INTEGER
;
1664 else if (u_strcmp(tokenValue
->fChars
, k_type_bin
) == 0) {
1667 else if (result
== RT_RESERVED
) {
1668 char tokenBuffer
[1024];
1669 u_austrncpy(tokenBuffer
, tokenValue
->fChars
, sizeof(tokenBuffer
));
1670 tokenBuffer
[sizeof(tokenBuffer
) - 1] = 0;
1671 *status
= U_INVALID_FORMAT_ERROR
;
1672 error(line
, "unknown resource type '%s'", tokenBuffer
);
1678 /* parse a non-top-level resource */
1679 static struct SResource
*
1680 parseResource(char *tag
, const struct UString
*comment
, UErrorCode
*status
)
1682 enum ETokenType token
;
1683 enum EResourceType resType
= RT_UNKNOWN
;
1684 ParseResourceFunction
*parseFunction
= NULL
;
1685 struct UString
*tokenValue
;
1689 token
= getToken(&tokenValue
, NULL
, &startline
, status
);
1692 printf(" resource %s at line %i \n", (tag
== NULL
) ? "(null)" : tag
, (int)startline
);
1695 /* name . [ ':' type ] '{' resource '}' */
1696 /* This function parses from the colon onwards. If the colon is present, parse the
1697 type then try to parse a resource of that type. If there is no explicit type,
1698 work it out using the lookahead tokens. */
1702 *status
= U_INVALID_FORMAT_ERROR
;
1703 error(startline
, "Unexpected EOF encountered");
1707 *status
= U_INVALID_FORMAT_ERROR
;
1711 resType
= parseResourceType(status
);
1712 expect(TOK_OPEN_BRACE
, &tokenValue
, NULL
, &startline
, status
);
1714 if (U_FAILURE(*status
))
1721 case TOK_OPEN_BRACE
:
1725 *status
= U_INVALID_FORMAT_ERROR
;
1726 error(startline
, "syntax error while reading a resource, expected '{' or ':'");
1730 if (resType
== RT_UNKNOWN
)
1732 /* No explicit type, so try to work it out. At this point, we've read the first '{'.
1733 We could have any of the following:
1734 { { => array (nested)
1736 { string , => string array
1738 commented by Jing/GCL
1743 { string :/{ => table
1744 { string } => string
1747 token
= peekToken(0, NULL
, &line
, NULL
,status
);
1749 if (U_FAILURE(*status
))
1754 /* Commented by Jing/GCL */
1755 /* if (token == TOK_OPEN_BRACE || token == TOK_COLON )*/
1756 if (token
== TOK_OPEN_BRACE
|| token
== TOK_COLON
||token
==TOK_CLOSE_BRACE
)
1760 else if (token
== TOK_STRING
)
1762 token
= peekToken(1, NULL
, &line
, NULL
, status
);
1764 if (U_FAILURE(*status
))
1771 case TOK_COMMA
: resType
= RT_ARRAY
; break;
1772 case TOK_OPEN_BRACE
: resType
= RT_TABLE
; break;
1773 case TOK_CLOSE_BRACE
: resType
= RT_STRING
; break;
1774 /* added by Jing/GCL to make table work when :table is omitted */
1775 case TOK_COLON
: resType
= RT_TABLE
; break;
1777 *status
= U_INVALID_FORMAT_ERROR
;
1778 error(line
, "Unexpected token after string, expected ',', '{' or '}'");
1784 *status
= U_INVALID_FORMAT_ERROR
;
1785 error(line
, "Unexpected token after '{'");
1789 /* printf("Type guessed as %s\n", resourceNames[resType]); */
1790 } else if(resType
== RT_TABLE_NO_FALLBACK
) {
1791 *status
= U_INVALID_FORMAT_ERROR
;
1792 error(startline
, "error: %s resource type not valid except on top bundle level", gResourceTypes
[resType
].nameChars
);
1796 /* We should now know what we need to parse next, so call the appropriate parser
1797 function and return. */
1798 parseFunction
= gResourceTypes
[resType
].parseFunction
;
1799 if (parseFunction
!= NULL
) {
1800 return parseFunction(tag
, startline
, comment
, status
);
1803 *status
= U_INTERNAL_PROGRAM_ERROR
;
1804 error(startline
, "internal error: %s resource type found and not handled", gResourceTypes
[resType
].nameChars
);
1810 /* parse the top-level resource */
1812 parse(UCHARBUF
*buf
, const char *inputDir
, const char *outputDir
, UErrorCode
*status
)
1814 struct UString
*tokenValue
;
1815 struct UString comment
;
1817 /* added by Jing/GCL */
1818 enum EResourceType bundleType
;
1819 enum ETokenType token
;
1821 initLookahead(buf
, status
);
1823 inputdir
= inputDir
;
1824 inputdirLength
= (inputdir
!= NULL
) ? (uint32_t)uprv_strlen(inputdir
) : 0;
1825 outputdir
= outputDir
;
1826 outputdirLength
= (outputdir
!= NULL
) ? (uint32_t)uprv_strlen(outputdir
) : 0;
1828 ustr_init(&comment
);
1829 expect(TOK_STRING
, &tokenValue
, &comment
, NULL
, status
);
1831 bundle
= bundle_open(&comment
, status
);
1833 if (bundle
== NULL
|| U_FAILURE(*status
))
1839 bundle_setlocale(bundle
, tokenValue
->fChars
, status
);
1840 /* Commented by Jing/GCL */
1841 /* expect(TOK_OPEN_BRACE, NULL, &line, status); */
1842 /* The following code is to make Empty bundle work no matter with :table specifer or not */
1843 token
= getToken(NULL
, NULL
, &line
, status
);
1844 if(token
==TOK_COLON
) {
1845 *status
=U_ZERO_ERROR
;
1846 bundleType
=parseResourceType(status
);
1848 if(isTable(bundleType
))
1850 expect(TOK_OPEN_BRACE
, NULL
, NULL
, &line
, status
);
1854 *status
=U_PARSE_ERROR
;
1855 error(line
, "parse error. Stopped parsing with %s", u_errorName(*status
));
1861 if(token
==TOK_OPEN_BRACE
)
1863 *status
=U_ZERO_ERROR
;
1864 bundleType
=RT_TABLE
;
1868 /* neither colon nor open brace */
1869 *status
=U_PARSE_ERROR
;
1870 bundleType
=RT_UNKNOWN
;
1871 error(line
, "parse error, did not find open-brace '{' or colon ':', stopped with %s", u_errorName(*status
));
1874 /* The above is added by Jing/GCL */
1876 if (U_FAILURE(*status
))
1878 bundle_close(bundle
, status
);
1882 if(bundleType
==RT_TABLE_NO_FALLBACK
) {
1884 * Parse a top-level table with the table(nofallback) declaration.
1885 * This is the same as a regular table, but also sets the
1886 * URES_ATT_NO_FALLBACK flag in indexes[URES_INDEX_ATTRIBUTES] .
1888 bundle
->noFallback
=TRUE
;
1890 /* top-level tables need not handle special table names like "collations" */
1891 realParseTable(bundle
->fRoot
, NULL
, line
, status
);
1893 if(dependencyArray
!=NULL
){
1894 table_add(bundle
->fRoot
, dependencyArray
, 0, status
);
1895 dependencyArray
= NULL
;
1897 if (U_FAILURE(*status
))
1899 bundle_close(bundle
, status
);
1900 array_close(dependencyArray
, status
);
1904 if (getToken(NULL
, NULL
, &line
, status
) != TOK_EOF
)
1906 warning(line
, "extraneous text after resource bundle (perhaps unmatched braces)");
1908 *status
= U_INVALID_FORMAT_ERROR
;