/src/icu/source/common/messagepattern.cpp
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | // © 2016 and later: Unicode, Inc. and others.  | 
2  |  | // License & terms of use: http://www.unicode.org/copyright.html  | 
3  |  | /*  | 
4  |  | *******************************************************************************  | 
5  |  | *   Copyright (C) 2011-2012, International Business Machines  | 
6  |  | *   Corporation and others.  All Rights Reserved.  | 
7  |  | *******************************************************************************  | 
8  |  | *   file name:  messagepattern.cpp  | 
9  |  | *   encoding:   UTF-8  | 
10  |  | *   tab size:   8 (not used)  | 
11  |  | *   indentation:4  | 
12  |  | *  | 
13  |  | *   created on: 2011mar14  | 
14  |  | *   created by: Markus W. Scherer  | 
15  |  | */  | 
16  |  |  | 
17  |  | #include "unicode/utypes.h"  | 
18  |  |  | 
19  |  | #if !UCONFIG_NO_FORMATTING  | 
20  |  |  | 
21  |  | #include "unicode/messagepattern.h"  | 
22  |  | #include "unicode/unistr.h"  | 
23  |  | #include "unicode/utf16.h"  | 
24  |  | #include "cmemory.h"  | 
25  |  | #include "cstring.h"  | 
26  |  | #include "messageimpl.h"  | 
27  |  | #include "patternprops.h"  | 
28  |  | #include "putilimp.h"  | 
29  |  | #include "uassert.h"  | 
30  |  |  | 
31  |  | U_NAMESPACE_BEGIN  | 
32  |  |  | 
33  |  | // Unicode character/code point constants ---------------------------------- ***  | 
34  |  |  | 
35  |  | static const UChar u_pound=0x23;  | 
36  |  | static const UChar u_apos=0x27;  | 
37  |  | static const UChar u_plus=0x2B;  | 
38  |  | static const UChar u_comma=0x2C;  | 
39  |  | static const UChar u_minus=0x2D;  | 
40  |  | static const UChar u_dot=0x2E;  | 
41  |  | static const UChar u_colon=0x3A;  | 
42  |  | static const UChar u_lessThan=0x3C;  | 
43  |  | static const UChar u_equal=0x3D;  | 
44  |  | static const UChar u_A=0x41;  | 
45  |  | static const UChar u_C=0x43;  | 
46  |  | static const UChar u_D=0x44;  | 
47  |  | static const UChar u_E=0x45;  | 
48  |  | static const UChar u_H=0x48;  | 
49  |  | static const UChar u_I=0x49;  | 
50  |  | static const UChar u_L=0x4C;  | 
51  |  | static const UChar u_N=0x4E;  | 
52  |  | static const UChar u_O=0x4F;  | 
53  |  | static const UChar u_P=0x50;  | 
54  |  | static const UChar u_R=0x52;  | 
55  |  | static const UChar u_S=0x53;  | 
56  |  | static const UChar u_T=0x54;  | 
57  |  | static const UChar u_U=0x55;  | 
58  |  | static const UChar u_Z=0x5A;  | 
59  |  | static const UChar u_a=0x61;  | 
60  |  | static const UChar u_c=0x63;  | 
61  |  | static const UChar u_d=0x64;  | 
62  |  | static const UChar u_e=0x65;  | 
63  |  | static const UChar u_f=0x66;  | 
64  |  | static const UChar u_h=0x68;  | 
65  |  | static const UChar u_i=0x69;  | 
66  |  | static const UChar u_l=0x6C;  | 
67  |  | static const UChar u_n=0x6E;  | 
68  |  | static const UChar u_o=0x6F;  | 
69  |  | static const UChar u_p=0x70;  | 
70  |  | static const UChar u_r=0x72;  | 
71  |  | static const UChar u_s=0x73;  | 
72  |  | static const UChar u_t=0x74;  | 
73  |  | static const UChar u_u=0x75;  | 
74  |  | static const UChar u_z=0x7A;  | 
75  |  | static const UChar u_leftCurlyBrace=0x7B;  | 
76  |  | static const UChar u_pipe=0x7C;  | 
77  |  | static const UChar u_rightCurlyBrace=0x7D;  | 
78  |  | static const UChar u_lessOrEqual=0x2264;  // U+2264 is <=  | 
79  |  |  | 
80  |  | static const UChar kOffsetColon[]={  // "offset:" | 
81  |  |     u_o, u_f, u_f, u_s, u_e, u_t, u_colon  | 
82  |  | };  | 
83  |  |  | 
84  |  | static const UChar kOther[]={  // "other" | 
85  |  |     u_o, u_t, u_h, u_e, u_r  | 
86  |  | };  | 
87  |  |  | 
88  |  | // MessagePatternList ------------------------------------------------------ ***  | 
89  |  |  | 
90  |  | template<typename T, int32_t stackCapacity>  | 
91  |  | class MessagePatternList : public UMemory { | 
92  |  | public:  | 
93  | 0  |     MessagePatternList() {}Unexecuted instantiation: icu_70::MessagePatternList<icu_70::MessagePattern::Part, 32>::MessagePatternList() Unexecuted instantiation: icu_70::MessagePatternList<double, 8>::MessagePatternList()  | 
94  |  |     void copyFrom(const MessagePatternList<T, stackCapacity> &other,  | 
95  |  |                   int32_t length,  | 
96  |  |                   UErrorCode &errorCode);  | 
97  |  |     UBool ensureCapacityForOneMore(int32_t oldLength, UErrorCode &errorCode);  | 
98  | 0  |     UBool equals(const MessagePatternList<T, stackCapacity> &other, int32_t length) const { | 
99  | 0  |         for(int32_t i=0; i<length; ++i) { | 
100  | 0  |             if(a[i]!=other.a[i]) { return FALSE; } | 
101  | 0  |         }  | 
102  | 0  |         return TRUE;  | 
103  | 0  |     }  | 
104  |  |  | 
105  |  |     MaybeStackArray<T, stackCapacity> a;  | 
106  |  | };  | 
107  |  |  | 
108  |  | template<typename T, int32_t stackCapacity>  | 
109  |  | void  | 
110  |  | MessagePatternList<T, stackCapacity>::copyFrom(  | 
111  |  |         const MessagePatternList<T, stackCapacity> &other,  | 
112  |  |         int32_t length,  | 
113  | 0  |         UErrorCode &errorCode) { | 
114  | 0  |     if(U_SUCCESS(errorCode) && length>0) { | 
115  | 0  |         if(length>a.getCapacity() && NULL==a.resize(length)) { | 
116  | 0  |             errorCode=U_MEMORY_ALLOCATION_ERROR;  | 
117  | 0  |             return;  | 
118  | 0  |         }  | 
119  | 0  |         uprv_memcpy(a.getAlias(), other.a.getAlias(), (size_t)length*sizeof(T));  | 
120  | 0  |     }  | 
121  | 0  | } Unexecuted instantiation: icu_70::MessagePatternList<icu_70::MessagePattern::Part, 32>::copyFrom(icu_70::MessagePatternList<icu_70::MessagePattern::Part, 32> const&, int, UErrorCode&) Unexecuted instantiation: icu_70::MessagePatternList<double, 8>::copyFrom(icu_70::MessagePatternList<double, 8> const&, int, UErrorCode&)  | 
122  |  |  | 
123  |  | template<typename T, int32_t stackCapacity>  | 
124  |  | UBool  | 
125  | 0  | MessagePatternList<T, stackCapacity>::ensureCapacityForOneMore(int32_t oldLength, UErrorCode &errorCode) { | 
126  | 0  |     if(U_FAILURE(errorCode)) { | 
127  | 0  |         return FALSE;  | 
128  | 0  |     }  | 
129  | 0  |     if(a.getCapacity()>oldLength || a.resize(2*oldLength, oldLength)!=NULL) { | 
130  | 0  |         return TRUE;  | 
131  | 0  |     }  | 
132  | 0  |     errorCode=U_MEMORY_ALLOCATION_ERROR;  | 
133  | 0  |     return FALSE;  | 
134  | 0  | } Unexecuted instantiation: icu_70::MessagePatternList<icu_70::MessagePattern::Part, 32>::ensureCapacityForOneMore(int, UErrorCode&) Unexecuted instantiation: icu_70::MessagePatternList<double, 8>::ensureCapacityForOneMore(int, UErrorCode&)  | 
135  |  |  | 
136  |  | // MessagePatternList specializations -------------------------------------- ***  | 
137  |  |  | 
138  |  | class MessagePatternDoubleList : public MessagePatternList<double, 8> { | 
139  |  | };  | 
140  |  |  | 
141  |  | class MessagePatternPartsList : public MessagePatternList<MessagePattern::Part, 32> { | 
142  |  | };  | 
143  |  |  | 
144  |  | // MessagePattern constructors etc. ---------------------------------------- ***  | 
145  |  |  | 
146  |  | MessagePattern::MessagePattern(UErrorCode &errorCode)  | 
147  | 0  |         : aposMode(UCONFIG_MSGPAT_DEFAULT_APOSTROPHE_MODE),  | 
148  | 0  |           partsList(NULL), parts(NULL), partsLength(0),  | 
149  | 0  |           numericValuesList(NULL), numericValues(NULL), numericValuesLength(0),  | 
150  | 0  |           hasArgNames(FALSE), hasArgNumbers(FALSE), needsAutoQuoting(FALSE) { | 
151  | 0  |     init(errorCode);  | 
152  | 0  | }  | 
153  |  |  | 
154  |  | MessagePattern::MessagePattern(UMessagePatternApostropheMode mode, UErrorCode &errorCode)  | 
155  | 0  |         : aposMode(mode),  | 
156  | 0  |           partsList(NULL), parts(NULL), partsLength(0),  | 
157  | 0  |           numericValuesList(NULL), numericValues(NULL), numericValuesLength(0),  | 
158  | 0  |           hasArgNames(FALSE), hasArgNumbers(FALSE), needsAutoQuoting(FALSE) { | 
159  | 0  |     init(errorCode);  | 
160  | 0  | }  | 
161  |  |  | 
162  |  | MessagePattern::MessagePattern(const UnicodeString &pattern, UParseError *parseError, UErrorCode &errorCode)  | 
163  | 0  |         : aposMode(UCONFIG_MSGPAT_DEFAULT_APOSTROPHE_MODE),  | 
164  | 0  |           partsList(NULL), parts(NULL), partsLength(0),  | 
165  | 0  |           numericValuesList(NULL), numericValues(NULL), numericValuesLength(0),  | 
166  | 0  |           hasArgNames(FALSE), hasArgNumbers(FALSE), needsAutoQuoting(FALSE) { | 
167  | 0  |     if(init(errorCode)) { | 
168  | 0  |         parse(pattern, parseError, errorCode);  | 
169  | 0  |     }  | 
170  | 0  | }  | 
171  |  |  | 
172  |  | UBool  | 
173  | 0  | MessagePattern::init(UErrorCode &errorCode) { | 
174  | 0  |     if(U_FAILURE(errorCode)) { | 
175  | 0  |         return FALSE;  | 
176  | 0  |     }  | 
177  | 0  |     partsList=new MessagePatternPartsList();  | 
178  | 0  |     if(partsList==NULL) { | 
179  | 0  |         errorCode=U_MEMORY_ALLOCATION_ERROR;  | 
180  | 0  |         return FALSE;  | 
181  | 0  |     }  | 
182  | 0  |     parts=partsList->a.getAlias();  | 
183  | 0  |     return TRUE;  | 
184  | 0  | }  | 
185  |  |  | 
186  |  | MessagePattern::MessagePattern(const MessagePattern &other)  | 
187  | 0  |         : UObject(other), aposMode(other.aposMode), msg(other.msg),  | 
188  | 0  |           partsList(NULL), parts(NULL), partsLength(0),  | 
189  | 0  |           numericValuesList(NULL), numericValues(NULL), numericValuesLength(0),  | 
190  | 0  |           hasArgNames(other.hasArgNames), hasArgNumbers(other.hasArgNumbers),  | 
191  | 0  |           needsAutoQuoting(other.needsAutoQuoting) { | 
192  | 0  |     UErrorCode errorCode=U_ZERO_ERROR;  | 
193  | 0  |     if(!copyStorage(other, errorCode)) { | 
194  | 0  |         clear();  | 
195  | 0  |     }  | 
196  | 0  | }  | 
197  |  |  | 
198  |  | MessagePattern &  | 
199  | 0  | MessagePattern::operator=(const MessagePattern &other) { | 
200  | 0  |     if(this==&other) { | 
201  | 0  |         return *this;  | 
202  | 0  |     }  | 
203  | 0  |     aposMode=other.aposMode;  | 
204  | 0  |     msg=other.msg;  | 
205  | 0  |     hasArgNames=other.hasArgNames;  | 
206  | 0  |     hasArgNumbers=other.hasArgNumbers;  | 
207  | 0  |     needsAutoQuoting=other.needsAutoQuoting;  | 
208  | 0  |     UErrorCode errorCode=U_ZERO_ERROR;  | 
209  | 0  |     if(!copyStorage(other, errorCode)) { | 
210  | 0  |         clear();  | 
211  | 0  |     }  | 
212  | 0  |     return *this;  | 
213  | 0  | }  | 
214  |  |  | 
215  |  | UBool  | 
216  | 0  | MessagePattern::copyStorage(const MessagePattern &other, UErrorCode &errorCode) { | 
217  | 0  |     if(U_FAILURE(errorCode)) { | 
218  | 0  |         return FALSE;  | 
219  | 0  |     }  | 
220  | 0  |     parts=NULL;  | 
221  | 0  |     partsLength=0;  | 
222  | 0  |     numericValues=NULL;  | 
223  | 0  |     numericValuesLength=0;  | 
224  | 0  |     if(partsList==NULL) { | 
225  | 0  |         partsList=new MessagePatternPartsList();  | 
226  | 0  |         if(partsList==NULL) { | 
227  | 0  |             errorCode=U_MEMORY_ALLOCATION_ERROR;  | 
228  | 0  |             return FALSE;  | 
229  | 0  |         }  | 
230  | 0  |         parts=partsList->a.getAlias();  | 
231  | 0  |     }  | 
232  | 0  |     if(other.partsLength>0) { | 
233  | 0  |         partsList->copyFrom(*other.partsList, other.partsLength, errorCode);  | 
234  | 0  |         if(U_FAILURE(errorCode)) { | 
235  | 0  |             return FALSE;  | 
236  | 0  |         }  | 
237  | 0  |         parts=partsList->a.getAlias();  | 
238  | 0  |         partsLength=other.partsLength;  | 
239  | 0  |     }  | 
240  | 0  |     if(other.numericValuesLength>0) { | 
241  | 0  |         if(numericValuesList==NULL) { | 
242  | 0  |             numericValuesList=new MessagePatternDoubleList();  | 
243  | 0  |             if(numericValuesList==NULL) { | 
244  | 0  |                 errorCode=U_MEMORY_ALLOCATION_ERROR;  | 
245  | 0  |                 return FALSE;  | 
246  | 0  |             }  | 
247  | 0  |             numericValues=numericValuesList->a.getAlias();  | 
248  | 0  |         }  | 
249  | 0  |         numericValuesList->copyFrom(  | 
250  | 0  |             *other.numericValuesList, other.numericValuesLength, errorCode);  | 
251  | 0  |         if(U_FAILURE(errorCode)) { | 
252  | 0  |             return FALSE;  | 
253  | 0  |         }  | 
254  | 0  |         numericValues=numericValuesList->a.getAlias();  | 
255  | 0  |         numericValuesLength=other.numericValuesLength;  | 
256  | 0  |     }  | 
257  | 0  |     return TRUE;  | 
258  | 0  | }  | 
259  |  |  | 
260  | 0  | MessagePattern::~MessagePattern() { | 
261  | 0  |     delete partsList;  | 
262  | 0  |     delete numericValuesList;  | 
263  | 0  | }  | 
264  |  |  | 
265  |  | // MessagePattern API ------------------------------------------------------ ***  | 
266  |  |  | 
267  |  | MessagePattern &  | 
268  | 0  | MessagePattern::parse(const UnicodeString &pattern, UParseError *parseError, UErrorCode &errorCode) { | 
269  | 0  |     preParse(pattern, parseError, errorCode);  | 
270  | 0  |     parseMessage(0, 0, 0, UMSGPAT_ARG_TYPE_NONE, parseError, errorCode);  | 
271  | 0  |     postParse();  | 
272  | 0  |     return *this;  | 
273  | 0  | }  | 
274  |  |  | 
275  |  | MessagePattern &  | 
276  |  | MessagePattern::parseChoiceStyle(const UnicodeString &pattern,  | 
277  | 0  |                                  UParseError *parseError, UErrorCode &errorCode) { | 
278  | 0  |     preParse(pattern, parseError, errorCode);  | 
279  | 0  |     parseChoiceStyle(0, 0, parseError, errorCode);  | 
280  | 0  |     postParse();  | 
281  | 0  |     return *this;  | 
282  | 0  | }  | 
283  |  |  | 
284  |  | MessagePattern &  | 
285  |  | MessagePattern::parsePluralStyle(const UnicodeString &pattern,  | 
286  | 0  |                                  UParseError *parseError, UErrorCode &errorCode) { | 
287  | 0  |     preParse(pattern, parseError, errorCode);  | 
288  | 0  |     parsePluralOrSelectStyle(UMSGPAT_ARG_TYPE_PLURAL, 0, 0, parseError, errorCode);  | 
289  | 0  |     postParse();  | 
290  | 0  |     return *this;  | 
291  | 0  | }  | 
292  |  |  | 
293  |  | MessagePattern &  | 
294  |  | MessagePattern::parseSelectStyle(const UnicodeString &pattern,  | 
295  | 0  |                                  UParseError *parseError, UErrorCode &errorCode) { | 
296  | 0  |     preParse(pattern, parseError, errorCode);  | 
297  | 0  |     parsePluralOrSelectStyle(UMSGPAT_ARG_TYPE_SELECT, 0, 0, parseError, errorCode);  | 
298  | 0  |     postParse();  | 
299  | 0  |     return *this;  | 
300  | 0  | }  | 
301  |  |  | 
302  |  | void  | 
303  | 0  | MessagePattern::clear() { | 
304  |  |     // Mostly the same as preParse().  | 
305  | 0  |     msg.remove();  | 
306  | 0  |     hasArgNames=hasArgNumbers=FALSE;  | 
307  | 0  |     needsAutoQuoting=FALSE;  | 
308  | 0  |     partsLength=0;  | 
309  | 0  |     numericValuesLength=0;  | 
310  | 0  | }  | 
311  |  |  | 
312  |  | bool  | 
313  | 0  | MessagePattern::operator==(const MessagePattern &other) const { | 
314  | 0  |     if(this==&other) { | 
315  | 0  |         return TRUE;  | 
316  | 0  |     }  | 
317  | 0  |     return  | 
318  | 0  |         aposMode==other.aposMode &&  | 
319  | 0  |         msg==other.msg &&  | 
320  |  |         // parts.equals(o.parts)  | 
321  | 0  |         partsLength==other.partsLength &&  | 
322  | 0  |         (partsLength==0 || partsList->equals(*other.partsList, partsLength));  | 
323  |  |     // No need to compare numericValues if msg and parts are the same.  | 
324  | 0  | }  | 
325  |  |  | 
326  |  | int32_t  | 
327  | 0  | MessagePattern::hashCode() const { | 
328  | 0  |     int32_t hash=(aposMode*37+msg.hashCode())*37+partsLength;  | 
329  | 0  |     for(int32_t i=0; i<partsLength; ++i) { | 
330  | 0  |         hash=hash*37+parts[i].hashCode();  | 
331  | 0  |     }  | 
332  | 0  |     return hash;  | 
333  | 0  | }  | 
334  |  |  | 
335  |  | int32_t  | 
336  | 0  | MessagePattern::validateArgumentName(const UnicodeString &name) { | 
337  | 0  |     if(!PatternProps::isIdentifier(name.getBuffer(), name.length())) { | 
338  | 0  |         return UMSGPAT_ARG_NAME_NOT_VALID;  | 
339  | 0  |     }  | 
340  | 0  |     return parseArgNumber(name, 0, name.length());  | 
341  | 0  | }  | 
342  |  |  | 
343  |  | UnicodeString  | 
344  | 0  | MessagePattern::autoQuoteApostropheDeep() const { | 
345  | 0  |     if(!needsAutoQuoting) { | 
346  | 0  |         return msg;  | 
347  | 0  |     }  | 
348  | 0  |     UnicodeString modified(msg);  | 
349  |  |     // Iterate backward so that the insertion indexes do not change.  | 
350  | 0  |     int32_t count=countParts();  | 
351  | 0  |     for(int32_t i=count; i>0;) { | 
352  | 0  |         const Part &part=getPart(--i);  | 
353  | 0  |         if(part.getType()==UMSGPAT_PART_TYPE_INSERT_CHAR) { | 
354  | 0  |            modified.insert(part.index, (UChar)part.value);  | 
355  | 0  |         }  | 
356  | 0  |     }  | 
357  | 0  |     return modified;  | 
358  | 0  | }  | 
359  |  |  | 
360  |  | double  | 
361  | 0  | MessagePattern::getNumericValue(const Part &part) const { | 
362  | 0  |     UMessagePatternPartType type=part.type;  | 
363  | 0  |     if(type==UMSGPAT_PART_TYPE_ARG_INT) { | 
364  | 0  |         return part.value;  | 
365  | 0  |     } else if(type==UMSGPAT_PART_TYPE_ARG_DOUBLE) { | 
366  | 0  |         return numericValues[part.value];  | 
367  | 0  |     } else { | 
368  | 0  |         return UMSGPAT_NO_NUMERIC_VALUE;  | 
369  | 0  |     }  | 
370  | 0  | }  | 
371  |  |  | 
372  |  | /**  | 
373  |  |   * Returns the "offset:" value of a PluralFormat argument, or 0 if none is specified.  | 
374  |  |   * @param pluralStart the index of the first PluralFormat argument style part. (0..countParts()-1)  | 
375  |  |   * @return the "offset:" value.  | 
376  |  |   * @draft ICU 4.8  | 
377  |  |   */  | 
378  |  | double  | 
379  | 0  | MessagePattern::getPluralOffset(int32_t pluralStart) const { | 
380  | 0  |     const Part &part=getPart(pluralStart);  | 
381  | 0  |     if(Part::hasNumericValue(part.type)) { | 
382  | 0  |         return getNumericValue(part);  | 
383  | 0  |     } else { | 
384  | 0  |         return 0;  | 
385  | 0  |     }  | 
386  | 0  | }  | 
387  |  |  | 
388  |  | // MessagePattern::Part ---------------------------------------------------- ***  | 
389  |  |  | 
390  |  | bool  | 
391  | 0  | MessagePattern::Part::operator==(const Part &other) const { | 
392  | 0  |     if(this==&other) { | 
393  | 0  |         return TRUE;  | 
394  | 0  |     }  | 
395  | 0  |     return  | 
396  | 0  |         type==other.type &&  | 
397  | 0  |         index==other.index &&  | 
398  | 0  |         length==other.length &&  | 
399  | 0  |         value==other.value &&  | 
400  | 0  |         limitPartIndex==other.limitPartIndex;  | 
401  | 0  | }  | 
402  |  |  | 
403  |  | // MessagePattern parser --------------------------------------------------- ***  | 
404  |  |  | 
405  |  | void  | 
406  | 0  | MessagePattern::preParse(const UnicodeString &pattern, UParseError *parseError, UErrorCode &errorCode) { | 
407  | 0  |     if(U_FAILURE(errorCode)) { | 
408  | 0  |         return;  | 
409  | 0  |     }  | 
410  | 0  |     if(parseError!=NULL) { | 
411  | 0  |         parseError->line=0;  | 
412  | 0  |         parseError->offset=0;  | 
413  | 0  |         parseError->preContext[0]=0;  | 
414  | 0  |         parseError->postContext[0]=0;  | 
415  | 0  |     }  | 
416  | 0  |     msg=pattern;  | 
417  | 0  |     hasArgNames=hasArgNumbers=FALSE;  | 
418  | 0  |     needsAutoQuoting=FALSE;  | 
419  | 0  |     partsLength=0;  | 
420  | 0  |     numericValuesLength=0;  | 
421  | 0  | }  | 
422  |  |  | 
423  |  | void  | 
424  | 0  | MessagePattern::postParse() { | 
425  | 0  |     if(partsList!=NULL) { | 
426  | 0  |         parts=partsList->a.getAlias();  | 
427  | 0  |     }  | 
428  | 0  |     if(numericValuesList!=NULL) { | 
429  | 0  |         numericValues=numericValuesList->a.getAlias();  | 
430  | 0  |     }  | 
431  | 0  | }  | 
432  |  |  | 
433  |  | int32_t  | 
434  |  | MessagePattern::parseMessage(int32_t index, int32_t msgStartLength,  | 
435  |  |                              int32_t nestingLevel, UMessagePatternArgType parentType,  | 
436  | 0  |                              UParseError *parseError, UErrorCode &errorCode) { | 
437  | 0  |     if(U_FAILURE(errorCode)) { | 
438  | 0  |         return 0;  | 
439  | 0  |     }  | 
440  | 0  |     if(nestingLevel>Part::MAX_VALUE) { | 
441  | 0  |         errorCode=U_INDEX_OUTOFBOUNDS_ERROR;  | 
442  | 0  |         return 0;  | 
443  | 0  |     }  | 
444  | 0  |     int32_t msgStart=partsLength;  | 
445  | 0  |     addPart(UMSGPAT_PART_TYPE_MSG_START, index, msgStartLength, nestingLevel, errorCode);  | 
446  | 0  |     index+=msgStartLength;  | 
447  | 0  |     for(;;) {  // while(index<msg.length()) with U_FAILURE(errorCode) check | 
448  | 0  |         if(U_FAILURE(errorCode)) { | 
449  | 0  |             return 0;  | 
450  | 0  |         }  | 
451  | 0  |         if(index>=msg.length()) { | 
452  | 0  |             break;  | 
453  | 0  |         }  | 
454  | 0  |         UChar c=msg.charAt(index++);  | 
455  | 0  |         if(c==u_apos) { | 
456  | 0  |             if(index==msg.length()) { | 
457  |  |                 // The apostrophe is the last character in the pattern.   | 
458  |  |                 // Add a Part for auto-quoting.  | 
459  | 0  |                 addPart(UMSGPAT_PART_TYPE_INSERT_CHAR, index, 0,  | 
460  | 0  |                         u_apos, errorCode);  // value=char to be inserted  | 
461  | 0  |                 needsAutoQuoting=TRUE;  | 
462  | 0  |             } else { | 
463  | 0  |                 c=msg.charAt(index);  | 
464  | 0  |                 if(c==u_apos) { | 
465  |  |                     // double apostrophe, skip the second one  | 
466  | 0  |                     addPart(UMSGPAT_PART_TYPE_SKIP_SYNTAX, index++, 1, 0, errorCode);  | 
467  | 0  |                 } else if(  | 
468  | 0  |                     aposMode==UMSGPAT_APOS_DOUBLE_REQUIRED ||  | 
469  | 0  |                     c==u_leftCurlyBrace || c==u_rightCurlyBrace ||  | 
470  | 0  |                     (parentType==UMSGPAT_ARG_TYPE_CHOICE && c==u_pipe) ||  | 
471  | 0  |                     (UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(parentType) && c==u_pound)  | 
472  | 0  |                 ) { | 
473  |  |                     // skip the quote-starting apostrophe  | 
474  | 0  |                     addPart(UMSGPAT_PART_TYPE_SKIP_SYNTAX, index-1, 1, 0, errorCode);  | 
475  |  |                     // find the end of the quoted literal text  | 
476  | 0  |                     for(;;) { | 
477  | 0  |                         index=msg.indexOf(u_apos, index+1);  | 
478  | 0  |                         if(index>=0) { | 
479  | 0  |                             if(/*(index+1)<msg.length() &&*/ msg.charAt(index+1)==u_apos) { | 
480  |  |                                 // double apostrophe inside quoted literal text  | 
481  |  |                                 // still encodes a single apostrophe, skip the second one  | 
482  | 0  |                                 addPart(UMSGPAT_PART_TYPE_SKIP_SYNTAX, ++index, 1, 0, errorCode);  | 
483  | 0  |                             } else { | 
484  |  |                                 // skip the quote-ending apostrophe  | 
485  | 0  |                                 addPart(UMSGPAT_PART_TYPE_SKIP_SYNTAX, index++, 1, 0, errorCode);  | 
486  | 0  |                                 break;  | 
487  | 0  |                             }  | 
488  | 0  |                         } else { | 
489  |  |                             // The quoted text reaches to the end of the of the message.  | 
490  | 0  |                             index=msg.length();  | 
491  |  |                             // Add a Part for auto-quoting.  | 
492  | 0  |                             addPart(UMSGPAT_PART_TYPE_INSERT_CHAR, index, 0,  | 
493  | 0  |                                     u_apos, errorCode);  // value=char to be inserted  | 
494  | 0  |                             needsAutoQuoting=TRUE;  | 
495  | 0  |                             break;  | 
496  | 0  |                         }  | 
497  | 0  |                     }  | 
498  | 0  |                 } else { | 
499  |  |                     // Interpret the apostrophe as literal text.  | 
500  |  |                     // Add a Part for auto-quoting.  | 
501  | 0  |                     addPart(UMSGPAT_PART_TYPE_INSERT_CHAR, index, 0,  | 
502  | 0  |                             u_apos, errorCode);  // value=char to be inserted  | 
503  | 0  |                     needsAutoQuoting=TRUE;  | 
504  | 0  |                 }  | 
505  | 0  |             }  | 
506  | 0  |         } else if(UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(parentType) && c==u_pound) { | 
507  |  |             // The unquoted # in a plural message fragment will be replaced  | 
508  |  |             // with the (number-offset).  | 
509  | 0  |             addPart(UMSGPAT_PART_TYPE_REPLACE_NUMBER, index-1, 1, 0, errorCode);  | 
510  | 0  |         } else if(c==u_leftCurlyBrace) { | 
511  | 0  |             index=parseArg(index-1, 1, nestingLevel, parseError, errorCode);  | 
512  | 0  |         } else if((nestingLevel>0 && c==u_rightCurlyBrace) ||  | 
513  | 0  |                   (parentType==UMSGPAT_ARG_TYPE_CHOICE && c==u_pipe)) { | 
514  |  |             // Finish the message before the terminator.  | 
515  |  |             // In a choice style, report the "}" substring only for the following ARG_LIMIT,  | 
516  |  |             // not for this MSG_LIMIT.  | 
517  | 0  |             int32_t limitLength=(parentType==UMSGPAT_ARG_TYPE_CHOICE && c==u_rightCurlyBrace) ? 0 : 1;  | 
518  | 0  |             addLimitPart(msgStart, UMSGPAT_PART_TYPE_MSG_LIMIT, index-1, limitLength,  | 
519  | 0  |                          nestingLevel, errorCode);  | 
520  | 0  |             if(parentType==UMSGPAT_ARG_TYPE_CHOICE) { | 
521  |  |                 // Let the choice style parser see the '}' or '|'.  | 
522  | 0  |                 return index-1;  | 
523  | 0  |             } else { | 
524  |  |                 // continue parsing after the '}'  | 
525  | 0  |                 return index;  | 
526  | 0  |             }  | 
527  | 0  |         }  // else: c is part of literal text  | 
528  | 0  |     }  | 
529  | 0  |     if(nestingLevel>0 && !inTopLevelChoiceMessage(nestingLevel, parentType)) { | 
530  | 0  |         setParseError(parseError, 0);  // Unmatched '{' braces in message. | 
531  | 0  |         errorCode=U_UNMATCHED_BRACES;  | 
532  | 0  |         return 0;  | 
533  | 0  |     }  | 
534  | 0  |     addLimitPart(msgStart, UMSGPAT_PART_TYPE_MSG_LIMIT, index, 0, nestingLevel, errorCode);  | 
535  | 0  |     return index;  | 
536  | 0  | }  | 
537  |  |  | 
538  |  | int32_t  | 
539  |  | MessagePattern::parseArg(int32_t index, int32_t argStartLength, int32_t nestingLevel,  | 
540  | 0  |                          UParseError *parseError, UErrorCode &errorCode) { | 
541  | 0  |     int32_t argStart=partsLength;  | 
542  | 0  |     UMessagePatternArgType argType=UMSGPAT_ARG_TYPE_NONE;  | 
543  | 0  |     addPart(UMSGPAT_PART_TYPE_ARG_START, index, argStartLength, argType, errorCode);  | 
544  | 0  |     if(U_FAILURE(errorCode)) { | 
545  | 0  |         return 0;  | 
546  | 0  |     }  | 
547  | 0  |     int32_t nameIndex=index=skipWhiteSpace(index+argStartLength);  | 
548  | 0  |     if(index==msg.length()) { | 
549  | 0  |         setParseError(parseError, 0);  // Unmatched '{' braces in message. | 
550  | 0  |         errorCode=U_UNMATCHED_BRACES;  | 
551  | 0  |         return 0;  | 
552  | 0  |     }  | 
553  |  |     // parse argument name or number  | 
554  | 0  |     index=skipIdentifier(index);  | 
555  | 0  |     int32_t number=parseArgNumber(nameIndex, index);  | 
556  | 0  |     if(number>=0) { | 
557  | 0  |         int32_t length=index-nameIndex;  | 
558  | 0  |         if(length>Part::MAX_LENGTH || number>Part::MAX_VALUE) { | 
559  | 0  |             setParseError(parseError, nameIndex);  // Argument number too large.  | 
560  | 0  |             errorCode=U_INDEX_OUTOFBOUNDS_ERROR;  | 
561  | 0  |             return 0;  | 
562  | 0  |         }  | 
563  | 0  |         hasArgNumbers=TRUE;  | 
564  | 0  |         addPart(UMSGPAT_PART_TYPE_ARG_NUMBER, nameIndex, length, number, errorCode);  | 
565  | 0  |     } else if(number==UMSGPAT_ARG_NAME_NOT_NUMBER) { | 
566  | 0  |         int32_t length=index-nameIndex;  | 
567  | 0  |         if(length>Part::MAX_LENGTH) { | 
568  | 0  |             setParseError(parseError, nameIndex);  // Argument name too long.  | 
569  | 0  |             errorCode=U_INDEX_OUTOFBOUNDS_ERROR;  | 
570  | 0  |             return 0;  | 
571  | 0  |         }  | 
572  | 0  |         hasArgNames=TRUE;  | 
573  | 0  |         addPart(UMSGPAT_PART_TYPE_ARG_NAME, nameIndex, length, 0, errorCode);  | 
574  | 0  |     } else {  // number<-1 (ARG_NAME_NOT_VALID) | 
575  | 0  |         setParseError(parseError, nameIndex);  // Bad argument syntax.  | 
576  | 0  |         errorCode=U_PATTERN_SYNTAX_ERROR;  | 
577  | 0  |         return 0;  | 
578  | 0  |     }  | 
579  | 0  |     index=skipWhiteSpace(index);  | 
580  | 0  |     if(index==msg.length()) { | 
581  | 0  |         setParseError(parseError, 0);  // Unmatched '{' braces in message. | 
582  | 0  |         errorCode=U_UNMATCHED_BRACES;  | 
583  | 0  |         return 0;  | 
584  | 0  |     }  | 
585  | 0  |     UChar c=msg.charAt(index);  | 
586  | 0  |     if(c==u_rightCurlyBrace) { | 
587  |  |         // all done  | 
588  | 0  |     } else if(c!=u_comma) { | 
589  | 0  |         setParseError(parseError, nameIndex);  // Bad argument syntax.  | 
590  | 0  |         errorCode=U_PATTERN_SYNTAX_ERROR;  | 
591  | 0  |         return 0;  | 
592  | 0  |     } else /* ',' */ { | 
593  |  |         // parse argument type: case-sensitive a-zA-Z  | 
594  | 0  |         int32_t typeIndex=index=skipWhiteSpace(index+1);  | 
595  | 0  |         while(index<msg.length() && isArgTypeChar(msg.charAt(index))) { | 
596  | 0  |             ++index;  | 
597  | 0  |         }  | 
598  | 0  |         int32_t length=index-typeIndex;  | 
599  | 0  |         index=skipWhiteSpace(index);  | 
600  | 0  |         if(index==msg.length()) { | 
601  | 0  |             setParseError(parseError, 0);  // Unmatched '{' braces in message. | 
602  | 0  |             errorCode=U_UNMATCHED_BRACES;  | 
603  | 0  |             return 0;  | 
604  | 0  |         }  | 
605  | 0  |         if(length==0 || ((c=msg.charAt(index))!=u_comma && c!=u_rightCurlyBrace)) { | 
606  | 0  |             setParseError(parseError, nameIndex);  // Bad argument syntax.  | 
607  | 0  |             errorCode=U_PATTERN_SYNTAX_ERROR;  | 
608  | 0  |             return 0;  | 
609  | 0  |         }  | 
610  | 0  |         if(length>Part::MAX_LENGTH) { | 
611  | 0  |             setParseError(parseError, nameIndex);  // Argument type name too long.  | 
612  | 0  |             errorCode=U_INDEX_OUTOFBOUNDS_ERROR;  | 
613  | 0  |             return 0;  | 
614  | 0  |         }  | 
615  | 0  |         argType=UMSGPAT_ARG_TYPE_SIMPLE;  | 
616  | 0  |         if(length==6) { | 
617  |  |             // case-insensitive comparisons for complex-type names  | 
618  | 0  |             if(isChoice(typeIndex)) { | 
619  | 0  |                 argType=UMSGPAT_ARG_TYPE_CHOICE;  | 
620  | 0  |             } else if(isPlural(typeIndex)) { | 
621  | 0  |                 argType=UMSGPAT_ARG_TYPE_PLURAL;  | 
622  | 0  |             } else if(isSelect(typeIndex)) { | 
623  | 0  |                 argType=UMSGPAT_ARG_TYPE_SELECT;  | 
624  | 0  |             }  | 
625  | 0  |         } else if(length==13) { | 
626  | 0  |             if(isSelect(typeIndex) && isOrdinal(typeIndex+6)) { | 
627  | 0  |                 argType=UMSGPAT_ARG_TYPE_SELECTORDINAL;  | 
628  | 0  |             }  | 
629  | 0  |         }  | 
630  |  |         // change the ARG_START type from NONE to argType  | 
631  | 0  |         partsList->a[argStart].value=(int16_t)argType;  | 
632  | 0  |         if(argType==UMSGPAT_ARG_TYPE_SIMPLE) { | 
633  | 0  |             addPart(UMSGPAT_PART_TYPE_ARG_TYPE, typeIndex, length, 0, errorCode);  | 
634  | 0  |         }  | 
635  |  |         // look for an argument style (pattern)  | 
636  | 0  |         if(c==u_rightCurlyBrace) { | 
637  | 0  |             if(argType!=UMSGPAT_ARG_TYPE_SIMPLE) { | 
638  | 0  |                 setParseError(parseError, nameIndex);  // No style field for complex argument.  | 
639  | 0  |                 errorCode=U_PATTERN_SYNTAX_ERROR;  | 
640  | 0  |                 return 0;  | 
641  | 0  |             }  | 
642  | 0  |         } else /* ',' */ { | 
643  | 0  |             ++index;  | 
644  | 0  |             if(argType==UMSGPAT_ARG_TYPE_SIMPLE) { | 
645  | 0  |                 index=parseSimpleStyle(index, parseError, errorCode);  | 
646  | 0  |             } else if(argType==UMSGPAT_ARG_TYPE_CHOICE) { | 
647  | 0  |                 index=parseChoiceStyle(index, nestingLevel, parseError, errorCode);  | 
648  | 0  |             } else { | 
649  | 0  |                 index=parsePluralOrSelectStyle(argType, index, nestingLevel, parseError, errorCode);  | 
650  | 0  |             }  | 
651  | 0  |         }  | 
652  | 0  |     }  | 
653  |  |     // Argument parsing stopped on the '}'.  | 
654  | 0  |     addLimitPart(argStart, UMSGPAT_PART_TYPE_ARG_LIMIT, index, 1, argType, errorCode);  | 
655  | 0  |     return index+1;  | 
656  | 0  | }  | 
657  |  |  | 
658  |  | int32_t  | 
659  | 0  | MessagePattern::parseSimpleStyle(int32_t index, UParseError *parseError, UErrorCode &errorCode) { | 
660  | 0  |     if(U_FAILURE(errorCode)) { | 
661  | 0  |         return 0;  | 
662  | 0  |     }  | 
663  | 0  |     int32_t start=index;  | 
664  | 0  |     int32_t nestedBraces=0;  | 
665  | 0  |     while(index<msg.length()) { | 
666  | 0  |         UChar c=msg.charAt(index++);  | 
667  | 0  |         if(c==u_apos) { | 
668  |  |             // Treat apostrophe as quoting but include it in the style part.  | 
669  |  |             // Find the end of the quoted literal text.  | 
670  | 0  |             index=msg.indexOf(u_apos, index);  | 
671  | 0  |             if(index<0) { | 
672  |  |                 // Quoted literal argument style text reaches to the end of the message.  | 
673  | 0  |                 setParseError(parseError, start);  | 
674  | 0  |                 errorCode=U_PATTERN_SYNTAX_ERROR;  | 
675  | 0  |                 return 0;  | 
676  | 0  |             }  | 
677  |  |             // skip the quote-ending apostrophe  | 
678  | 0  |             ++index;  | 
679  | 0  |         } else if(c==u_leftCurlyBrace) { | 
680  | 0  |             ++nestedBraces;  | 
681  | 0  |         } else if(c==u_rightCurlyBrace) { | 
682  | 0  |             if(nestedBraces>0) { | 
683  | 0  |                 --nestedBraces;  | 
684  | 0  |             } else { | 
685  | 0  |                 int32_t length=--index-start;  | 
686  | 0  |                 if(length>Part::MAX_LENGTH) { | 
687  | 0  |                     setParseError(parseError, start);  // Argument style text too long.  | 
688  | 0  |                     errorCode=U_INDEX_OUTOFBOUNDS_ERROR;  | 
689  | 0  |                     return 0;  | 
690  | 0  |                 }  | 
691  | 0  |                 addPart(UMSGPAT_PART_TYPE_ARG_STYLE, start, length, 0, errorCode);  | 
692  | 0  |                 return index;  | 
693  | 0  |             }  | 
694  | 0  |         }  // c is part of literal text  | 
695  | 0  |     }  | 
696  | 0  |     setParseError(parseError, 0);  // Unmatched '{' braces in message. | 
697  | 0  |     errorCode=U_UNMATCHED_BRACES;  | 
698  | 0  |     return 0;  | 
699  | 0  | }  | 
700  |  |  | 
701  |  | int32_t  | 
702  |  | MessagePattern::parseChoiceStyle(int32_t index, int32_t nestingLevel,  | 
703  | 0  |                                  UParseError *parseError, UErrorCode &errorCode) { | 
704  | 0  |     if(U_FAILURE(errorCode)) { | 
705  | 0  |         return 0;  | 
706  | 0  |     }  | 
707  | 0  |     int32_t start=index;  | 
708  | 0  |     index=skipWhiteSpace(index);  | 
709  | 0  |     if(index==msg.length() || msg.charAt(index)==u_rightCurlyBrace) { | 
710  | 0  |         setParseError(parseError, 0);  // Missing choice argument pattern.  | 
711  | 0  |         errorCode=U_PATTERN_SYNTAX_ERROR;  | 
712  | 0  |         return 0;  | 
713  | 0  |     }  | 
714  | 0  |     for(;;) { | 
715  |  |         // The choice argument style contains |-separated (number, separator, message) triples.  | 
716  |  |         // Parse the number.  | 
717  | 0  |         int32_t numberIndex=index;  | 
718  | 0  |         index=skipDouble(index);  | 
719  | 0  |         int32_t length=index-numberIndex;  | 
720  | 0  |         if(length==0) { | 
721  | 0  |             setParseError(parseError, start);  // Bad choice pattern syntax.  | 
722  | 0  |             errorCode=U_PATTERN_SYNTAX_ERROR;  | 
723  | 0  |             return 0;  | 
724  | 0  |         }  | 
725  | 0  |         if(length>Part::MAX_LENGTH) { | 
726  | 0  |             setParseError(parseError, numberIndex);  // Choice number too long.  | 
727  | 0  |             errorCode=U_INDEX_OUTOFBOUNDS_ERROR;  | 
728  | 0  |             return 0;  | 
729  | 0  |         }  | 
730  | 0  |         parseDouble(numberIndex, index, TRUE, parseError, errorCode);  // adds ARG_INT or ARG_DOUBLE  | 
731  | 0  |         if(U_FAILURE(errorCode)) { | 
732  | 0  |             return 0;  | 
733  | 0  |         }  | 
734  |  |         // Parse the separator.  | 
735  | 0  |         index=skipWhiteSpace(index);  | 
736  | 0  |         if(index==msg.length()) { | 
737  | 0  |             setParseError(parseError, start);  // Bad choice pattern syntax.  | 
738  | 0  |             errorCode=U_PATTERN_SYNTAX_ERROR;  | 
739  | 0  |             return 0;  | 
740  | 0  |         }  | 
741  | 0  |         UChar c=msg.charAt(index);  | 
742  | 0  |         if(!(c==u_pound || c==u_lessThan || c==u_lessOrEqual)) {  // U+2264 is <= | 
743  | 0  |             setParseError(parseError, start);  // Expected choice separator (#<\u2264) instead of c.  | 
744  | 0  |             errorCode=U_PATTERN_SYNTAX_ERROR;  | 
745  | 0  |             return 0;  | 
746  | 0  |         }  | 
747  | 0  |         addPart(UMSGPAT_PART_TYPE_ARG_SELECTOR, index, 1, 0, errorCode);  | 
748  |  |         // Parse the message fragment.  | 
749  | 0  |         index=parseMessage(++index, 0, nestingLevel+1, UMSGPAT_ARG_TYPE_CHOICE, parseError, errorCode);  | 
750  | 0  |         if(U_FAILURE(errorCode)) { | 
751  | 0  |             return 0;  | 
752  | 0  |         }  | 
753  |  |         // parseMessage(..., CHOICE) returns the index of the terminator, or msg.length().  | 
754  | 0  |         if(index==msg.length()) { | 
755  | 0  |             return index;  | 
756  | 0  |         }  | 
757  | 0  |         if(msg.charAt(index)==u_rightCurlyBrace) { | 
758  | 0  |             if(!inMessageFormatPattern(nestingLevel)) { | 
759  | 0  |                 setParseError(parseError, start);  // Bad choice pattern syntax.  | 
760  | 0  |                 errorCode=U_PATTERN_SYNTAX_ERROR;  | 
761  | 0  |                 return 0;  | 
762  | 0  |             }  | 
763  | 0  |             return index;  | 
764  | 0  |         }  // else the terminator is '|'  | 
765  | 0  |         index=skipWhiteSpace(index+1);  | 
766  | 0  |     }  | 
767  | 0  | }  | 
768  |  |  | 
769  |  | int32_t  | 
770  |  | MessagePattern::parsePluralOrSelectStyle(UMessagePatternArgType argType,  | 
771  |  |                                          int32_t index, int32_t nestingLevel,  | 
772  | 0  |                                          UParseError *parseError, UErrorCode &errorCode) { | 
773  | 0  |     if(U_FAILURE(errorCode)) { | 
774  | 0  |         return 0;  | 
775  | 0  |     }  | 
776  | 0  |     int32_t start=index;  | 
777  | 0  |     UBool isEmpty=TRUE;  | 
778  | 0  |     UBool hasOther=FALSE;  | 
779  | 0  |     for(;;) { | 
780  |  |         // First, collect the selector looking for a small set of terminators.  | 
781  |  |         // It would be a little faster to consider the syntax of each possible  | 
782  |  |         // token right here, but that makes the code too complicated.  | 
783  | 0  |         index=skipWhiteSpace(index);  | 
784  | 0  |         UBool eos=index==msg.length();  | 
785  | 0  |         if(eos || msg.charAt(index)==u_rightCurlyBrace) { | 
786  | 0  |             if(eos==inMessageFormatPattern(nestingLevel)) { | 
787  | 0  |                 setParseError(parseError, start);  // Bad plural/select pattern syntax.  | 
788  | 0  |                 errorCode=U_PATTERN_SYNTAX_ERROR;  | 
789  | 0  |                 return 0;  | 
790  | 0  |             }  | 
791  | 0  |             if(!hasOther) { | 
792  | 0  |                 setParseError(parseError, 0);  // Missing 'other' keyword in plural/select pattern.  | 
793  | 0  |                 errorCode=U_DEFAULT_KEYWORD_MISSING;  | 
794  | 0  |                 return 0;  | 
795  | 0  |             }  | 
796  | 0  |             return index;  | 
797  | 0  |         }  | 
798  | 0  |         int32_t selectorIndex=index;  | 
799  | 0  |         if(UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType) && msg.charAt(selectorIndex)==u_equal) { | 
800  |  |             // explicit-value plural selector: =double  | 
801  | 0  |             index=skipDouble(index+1);  | 
802  | 0  |             int32_t length=index-selectorIndex;  | 
803  | 0  |             if(length==1) { | 
804  | 0  |                 setParseError(parseError, start);  // Bad plural/select pattern syntax.  | 
805  | 0  |                 errorCode=U_PATTERN_SYNTAX_ERROR;  | 
806  | 0  |                 return 0;  | 
807  | 0  |             }  | 
808  | 0  |             if(length>Part::MAX_LENGTH) { | 
809  | 0  |                 setParseError(parseError, selectorIndex);  // Argument selector too long.  | 
810  | 0  |                 errorCode=U_INDEX_OUTOFBOUNDS_ERROR;  | 
811  | 0  |                 return 0;  | 
812  | 0  |             }  | 
813  | 0  |             addPart(UMSGPAT_PART_TYPE_ARG_SELECTOR, selectorIndex, length, 0, errorCode);  | 
814  | 0  |             parseDouble(selectorIndex+1, index, FALSE,  | 
815  | 0  |                         parseError, errorCode);  // adds ARG_INT or ARG_DOUBLE  | 
816  | 0  |         } else { | 
817  | 0  |             index=skipIdentifier(index);  | 
818  | 0  |             int32_t length=index-selectorIndex;  | 
819  | 0  |             if(length==0) { | 
820  | 0  |                 setParseError(parseError, start);  // Bad plural/select pattern syntax.  | 
821  | 0  |                 errorCode=U_PATTERN_SYNTAX_ERROR;  | 
822  | 0  |                 return 0;  | 
823  | 0  |             }  | 
824  |  |             // Note: The ':' in "offset:" is just beyond the skipIdentifier() range.  | 
825  | 0  |             if( UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType) && length==6 && index<msg.length() &&  | 
826  | 0  |                 0==msg.compare(selectorIndex, 7, kOffsetColon, 0, 7)  | 
827  | 0  |             ) { | 
828  |  |                 // plural offset, not a selector  | 
829  | 0  |                 if(!isEmpty) { | 
830  |  |                     // Plural argument 'offset:' (if present) must precede key-message pairs.  | 
831  | 0  |                     setParseError(parseError, start);  | 
832  | 0  |                     errorCode=U_PATTERN_SYNTAX_ERROR;  | 
833  | 0  |                     return 0;  | 
834  | 0  |                 }  | 
835  |  |                 // allow whitespace between offset: and its value  | 
836  | 0  |                 int32_t valueIndex=skipWhiteSpace(index+1);  // The ':' is at index.  | 
837  | 0  |                 index=skipDouble(valueIndex);  | 
838  | 0  |                 if(index==valueIndex) { | 
839  | 0  |                     setParseError(parseError, start);  // Missing value for plural 'offset:'.  | 
840  | 0  |                     errorCode=U_PATTERN_SYNTAX_ERROR;  | 
841  | 0  |                     return 0;  | 
842  | 0  |                 }  | 
843  | 0  |                 if((index-valueIndex)>Part::MAX_LENGTH) { | 
844  | 0  |                     setParseError(parseError, valueIndex);  // Plural offset value too long.  | 
845  | 0  |                     errorCode=U_INDEX_OUTOFBOUNDS_ERROR;  | 
846  | 0  |                     return 0;  | 
847  | 0  |                 }  | 
848  | 0  |                 parseDouble(valueIndex, index, FALSE,  | 
849  | 0  |                             parseError, errorCode);  // adds ARG_INT or ARG_DOUBLE  | 
850  | 0  |                 if(U_FAILURE(errorCode)) { | 
851  | 0  |                     return 0;  | 
852  | 0  |                 }  | 
853  | 0  |                 isEmpty=FALSE;  | 
854  | 0  |                 continue;  // no message fragment after the offset  | 
855  | 0  |             } else { | 
856  |  |                 // normal selector word  | 
857  | 0  |                 if(length>Part::MAX_LENGTH) { | 
858  | 0  |                     setParseError(parseError, selectorIndex);  // Argument selector too long.  | 
859  | 0  |                     errorCode=U_INDEX_OUTOFBOUNDS_ERROR;  | 
860  | 0  |                     return 0;  | 
861  | 0  |                 }  | 
862  | 0  |                 addPart(UMSGPAT_PART_TYPE_ARG_SELECTOR, selectorIndex, length, 0, errorCode);  | 
863  | 0  |                 if(0==msg.compare(selectorIndex, length, kOther, 0, 5)) { | 
864  | 0  |                     hasOther=TRUE;  | 
865  | 0  |                 }  | 
866  | 0  |             }  | 
867  | 0  |         }  | 
868  | 0  |         if(U_FAILURE(errorCode)) { | 
869  | 0  |             return 0;  | 
870  | 0  |         }  | 
871  |  |  | 
872  |  |         // parse the message fragment following the selector  | 
873  | 0  |         index=skipWhiteSpace(index);  | 
874  | 0  |         if(index==msg.length() || msg.charAt(index)!=u_leftCurlyBrace) { | 
875  | 0  |             setParseError(parseError, selectorIndex);  // No message fragment after plural/select selector.  | 
876  | 0  |             errorCode=U_PATTERN_SYNTAX_ERROR;  | 
877  | 0  |             return 0;  | 
878  | 0  |         }  | 
879  | 0  |         index=parseMessage(index, 1, nestingLevel+1, argType, parseError, errorCode);  | 
880  | 0  |         if(U_FAILURE(errorCode)) { | 
881  | 0  |             return 0;  | 
882  | 0  |         }  | 
883  | 0  |         isEmpty=FALSE;  | 
884  | 0  |     }  | 
885  | 0  | }  | 
886  |  |  | 
887  |  | int32_t  | 
888  | 0  | MessagePattern::parseArgNumber(const UnicodeString &s, int32_t start, int32_t limit) { | 
889  |  |     // If the identifier contains only ASCII digits, then it is an argument _number_  | 
890  |  |     // and must not have leading zeros (except "0" itself).  | 
891  |  |     // Otherwise it is an argument _name_.  | 
892  | 0  |     if(start>=limit) { | 
893  | 0  |         return UMSGPAT_ARG_NAME_NOT_VALID;  | 
894  | 0  |     }  | 
895  | 0  |     int32_t number;  | 
896  |  |     // Defer numeric errors until we know there are only digits.  | 
897  | 0  |     UBool badNumber;  | 
898  | 0  |     UChar c=s.charAt(start++);  | 
899  | 0  |     if(c==0x30) { | 
900  | 0  |         if(start==limit) { | 
901  | 0  |             return 0;  | 
902  | 0  |         } else { | 
903  | 0  |             number=0;  | 
904  | 0  |             badNumber=TRUE;  // leading zero  | 
905  | 0  |         }  | 
906  | 0  |     } else if(0x31<=c && c<=0x39) { | 
907  | 0  |         number=c-0x30;  | 
908  | 0  |         badNumber=FALSE;  | 
909  | 0  |     } else { | 
910  | 0  |         return UMSGPAT_ARG_NAME_NOT_NUMBER;  | 
911  | 0  |     }  | 
912  | 0  |     while(start<limit) { | 
913  | 0  |         c=s.charAt(start++);  | 
914  | 0  |         if(0x30<=c && c<=0x39) { | 
915  | 0  |             if(number>=INT32_MAX/10) { | 
916  | 0  |                 badNumber=TRUE;  // overflow  | 
917  | 0  |             }  | 
918  | 0  |             number=number*10+(c-0x30);  | 
919  | 0  |         } else { | 
920  | 0  |             return UMSGPAT_ARG_NAME_NOT_NUMBER;  | 
921  | 0  |         }  | 
922  | 0  |     }  | 
923  |  |     // There are only ASCII digits.  | 
924  | 0  |     if(badNumber) { | 
925  | 0  |         return UMSGPAT_ARG_NAME_NOT_VALID;  | 
926  | 0  |     } else { | 
927  | 0  |         return number;  | 
928  | 0  |     }  | 
929  | 0  | }  | 
930  |  |  | 
931  |  | void  | 
932  |  | MessagePattern::parseDouble(int32_t start, int32_t limit, UBool allowInfinity,  | 
933  | 0  |                             UParseError *parseError, UErrorCode &errorCode) { | 
934  | 0  |     if(U_FAILURE(errorCode)) { | 
935  | 0  |         return;  | 
936  | 0  |     }  | 
937  | 0  |     U_ASSERT(start<limit);  | 
938  |  |     // fake loop for easy exit and single throw statement  | 
939  | 0  |     for(;;) { /*loop doesn't iterate*/ | 
940  |  |         // fast path for small integers and infinity  | 
941  | 0  |         int32_t value=0;  | 
942  | 0  |         int32_t isNegative=0;  // not boolean so that we can easily add it to value  | 
943  | 0  |         int32_t index=start;  | 
944  | 0  |         UChar c=msg.charAt(index++);  | 
945  | 0  |         if(c==u_minus) { | 
946  | 0  |             isNegative=1;  | 
947  | 0  |             if(index==limit) { | 
948  | 0  |                 break;  // no number  | 
949  | 0  |             }  | 
950  | 0  |             c=msg.charAt(index++);  | 
951  | 0  |         } else if(c==u_plus) { | 
952  | 0  |             if(index==limit) { | 
953  | 0  |                 break;  // no number  | 
954  | 0  |             }  | 
955  | 0  |             c=msg.charAt(index++);  | 
956  | 0  |         }  | 
957  | 0  |         if(c==0x221e) {  // infinity | 
958  | 0  |             if(allowInfinity && index==limit) { | 
959  | 0  |                 double infinity=uprv_getInfinity();  | 
960  | 0  |                 addArgDoublePart(  | 
961  | 0  |                     isNegative!=0 ? -infinity : infinity,  | 
962  | 0  |                     start, limit-start, errorCode);  | 
963  | 0  |                 return;  | 
964  | 0  |             } else { | 
965  | 0  |                 break;  | 
966  | 0  |             }  | 
967  | 0  |         }  | 
968  |  |         // try to parse the number as a small integer but fall back to a double  | 
969  | 0  |         while('0'<=c && c<='9') { | 
970  | 0  |             value=value*10+(c-'0');  | 
971  | 0  |             if(value>(Part::MAX_VALUE+isNegative)) { | 
972  | 0  |                 break;  // not a small-enough integer  | 
973  | 0  |             }  | 
974  | 0  |             if(index==limit) { | 
975  | 0  |                 addPart(UMSGPAT_PART_TYPE_ARG_INT, start, limit-start,  | 
976  | 0  |                         isNegative!=0 ? -value : value, errorCode);  | 
977  | 0  |                 return;  | 
978  | 0  |             }  | 
979  | 0  |             c=msg.charAt(index++);  | 
980  | 0  |         }  | 
981  |  |         // Let Double.parseDouble() throw a NumberFormatException.  | 
982  | 0  |         char numberChars[128];  | 
983  | 0  |         int32_t capacity=(int32_t)sizeof(numberChars);  | 
984  | 0  |         int32_t length=limit-start;  | 
985  | 0  |         if(length>=capacity) { | 
986  | 0  |             break;  // number too long  | 
987  | 0  |         }  | 
988  | 0  |         msg.extract(start, length, numberChars, capacity, US_INV);  | 
989  | 0  |         if((int32_t)uprv_strlen(numberChars)<length) { | 
990  | 0  |             break;  // contains non-invariant character that was turned into NUL  | 
991  | 0  |         }  | 
992  | 0  |         char *end;  | 
993  | 0  |         double numericValue=uprv_strtod(numberChars, &end);  | 
994  | 0  |         if(end!=(numberChars+length)) { | 
995  | 0  |             break;  // parsing error  | 
996  | 0  |         }  | 
997  | 0  |         addArgDoublePart(numericValue, start, length, errorCode);  | 
998  | 0  |         return;  | 
999  | 0  |     }  | 
1000  | 0  |     setParseError(parseError, start /*, limit*/);  // Bad syntax for numeric value.  | 
1001  | 0  |     errorCode=U_PATTERN_SYNTAX_ERROR;  | 
1002  | 0  |     return;  | 
1003  | 0  | }  | 
1004  |  |  | 
1005  |  | int32_t  | 
1006  | 0  | MessagePattern::skipWhiteSpace(int32_t index) { | 
1007  | 0  |     const UChar *s=msg.getBuffer();  | 
1008  | 0  |     int32_t msgLength=msg.length();  | 
1009  | 0  |     const UChar *t=PatternProps::skipWhiteSpace(s+index, msgLength-index);  | 
1010  | 0  |     return (int32_t)(t-s);  | 
1011  | 0  | }  | 
1012  |  |  | 
1013  |  | int32_t  | 
1014  | 0  | MessagePattern::skipIdentifier(int32_t index) { | 
1015  | 0  |     const UChar *s=msg.getBuffer();  | 
1016  | 0  |     int32_t msgLength=msg.length();  | 
1017  | 0  |     const UChar *t=PatternProps::skipIdentifier(s+index, msgLength-index);  | 
1018  | 0  |     return (int32_t)(t-s);  | 
1019  | 0  | }  | 
1020  |  |  | 
1021  |  | int32_t  | 
1022  | 0  | MessagePattern::skipDouble(int32_t index) { | 
1023  | 0  |     int32_t msgLength=msg.length();  | 
1024  | 0  |     while(index<msgLength) { | 
1025  | 0  |         UChar c=msg.charAt(index);  | 
1026  |  |         // U+221E: Allow the infinity symbol, for ChoiceFormat patterns.  | 
1027  | 0  |         if((c<0x30 && c!=u_plus && c!=u_minus && c!=u_dot) || (c>0x39 && c!=u_e && c!=u_E && c!=0x221e)) { | 
1028  | 0  |             break;  | 
1029  | 0  |         }  | 
1030  | 0  |         ++index;  | 
1031  | 0  |     }  | 
1032  | 0  |     return index;  | 
1033  | 0  | }  | 
1034  |  |  | 
1035  |  | UBool  | 
1036  | 0  | MessagePattern::isArgTypeChar(UChar32 c) { | 
1037  | 0  |     return (u_a<=c && c<=u_z) || (u_A<=c && c<=u_Z);  | 
1038  | 0  | }  | 
1039  |  |  | 
1040  |  | UBool  | 
1041  | 0  | MessagePattern::isChoice(int32_t index) { | 
1042  | 0  |     UChar c;  | 
1043  | 0  |     return  | 
1044  | 0  |         ((c=msg.charAt(index++))==u_c || c==u_C) &&  | 
1045  | 0  |         ((c=msg.charAt(index++))==u_h || c==u_H) &&  | 
1046  | 0  |         ((c=msg.charAt(index++))==u_o || c==u_O) &&  | 
1047  | 0  |         ((c=msg.charAt(index++))==u_i || c==u_I) &&  | 
1048  | 0  |         ((c=msg.charAt(index++))==u_c || c==u_C) &&  | 
1049  | 0  |         ((c=msg.charAt(index))==u_e || c==u_E);  | 
1050  | 0  | }  | 
1051  |  |  | 
1052  |  | UBool  | 
1053  | 0  | MessagePattern::isPlural(int32_t index) { | 
1054  | 0  |     UChar c;  | 
1055  | 0  |     return  | 
1056  | 0  |         ((c=msg.charAt(index++))==u_p || c==u_P) &&  | 
1057  | 0  |         ((c=msg.charAt(index++))==u_l || c==u_L) &&  | 
1058  | 0  |         ((c=msg.charAt(index++))==u_u || c==u_U) &&  | 
1059  | 0  |         ((c=msg.charAt(index++))==u_r || c==u_R) &&  | 
1060  | 0  |         ((c=msg.charAt(index++))==u_a || c==u_A) &&  | 
1061  | 0  |         ((c=msg.charAt(index))==u_l || c==u_L);  | 
1062  | 0  | }  | 
1063  |  |  | 
1064  |  | UBool  | 
1065  | 0  | MessagePattern::isSelect(int32_t index) { | 
1066  | 0  |     UChar c;  | 
1067  | 0  |     return  | 
1068  | 0  |         ((c=msg.charAt(index++))==u_s || c==u_S) &&  | 
1069  | 0  |         ((c=msg.charAt(index++))==u_e || c==u_E) &&  | 
1070  | 0  |         ((c=msg.charAt(index++))==u_l || c==u_L) &&  | 
1071  | 0  |         ((c=msg.charAt(index++))==u_e || c==u_E) &&  | 
1072  | 0  |         ((c=msg.charAt(index++))==u_c || c==u_C) &&  | 
1073  | 0  |         ((c=msg.charAt(index))==u_t || c==u_T);  | 
1074  | 0  | }  | 
1075  |  |  | 
1076  |  | UBool  | 
1077  | 0  | MessagePattern::isOrdinal(int32_t index) { | 
1078  | 0  |     UChar c;  | 
1079  | 0  |     return  | 
1080  | 0  |         ((c=msg.charAt(index++))==u_o || c==u_O) &&  | 
1081  | 0  |         ((c=msg.charAt(index++))==u_r || c==u_R) &&  | 
1082  | 0  |         ((c=msg.charAt(index++))==u_d || c==u_D) &&  | 
1083  | 0  |         ((c=msg.charAt(index++))==u_i || c==u_I) &&  | 
1084  | 0  |         ((c=msg.charAt(index++))==u_n || c==u_N) &&  | 
1085  | 0  |         ((c=msg.charAt(index++))==u_a || c==u_A) &&  | 
1086  | 0  |         ((c=msg.charAt(index))==u_l || c==u_L);  | 
1087  | 0  | }  | 
1088  |  |  | 
1089  |  | UBool  | 
1090  | 0  | MessagePattern::inMessageFormatPattern(int32_t nestingLevel) { | 
1091  | 0  |     return nestingLevel>0 || partsList->a[0].type==UMSGPAT_PART_TYPE_MSG_START;  | 
1092  | 0  | }  | 
1093  |  |  | 
1094  |  | UBool  | 
1095  | 0  | MessagePattern::inTopLevelChoiceMessage(int32_t nestingLevel, UMessagePatternArgType parentType) { | 
1096  | 0  |     return  | 
1097  | 0  |         nestingLevel==1 &&  | 
1098  | 0  |         parentType==UMSGPAT_ARG_TYPE_CHOICE &&  | 
1099  | 0  |         partsList->a[0].type!=UMSGPAT_PART_TYPE_MSG_START;  | 
1100  | 0  | }  | 
1101  |  |  | 
1102  |  | void  | 
1103  |  | MessagePattern::addPart(UMessagePatternPartType type, int32_t index, int32_t length,  | 
1104  | 0  |                         int32_t value, UErrorCode &errorCode) { | 
1105  | 0  |     if(partsList->ensureCapacityForOneMore(partsLength, errorCode)) { | 
1106  | 0  |         Part &part=partsList->a[partsLength++];  | 
1107  | 0  |         part.type=type;  | 
1108  | 0  |         part.index=index;  | 
1109  | 0  |         part.length=(uint16_t)length;  | 
1110  | 0  |         part.value=(int16_t)value;  | 
1111  | 0  |         part.limitPartIndex=0;  | 
1112  | 0  |     }  | 
1113  | 0  | }  | 
1114  |  |  | 
1115  |  | void  | 
1116  |  | MessagePattern::addLimitPart(int32_t start,  | 
1117  |  |                              UMessagePatternPartType type, int32_t index, int32_t length,  | 
1118  | 0  |                              int32_t value, UErrorCode &errorCode) { | 
1119  | 0  |     partsList->a[start].limitPartIndex=partsLength;  | 
1120  | 0  |     addPart(type, index, length, value, errorCode);  | 
1121  | 0  | }  | 
1122  |  |  | 
1123  |  | void  | 
1124  |  | MessagePattern::addArgDoublePart(double numericValue, int32_t start, int32_t length,  | 
1125  | 0  |                                  UErrorCode &errorCode) { | 
1126  | 0  |     if(U_FAILURE(errorCode)) { | 
1127  | 0  |         return;  | 
1128  | 0  |     }  | 
1129  | 0  |     int32_t numericIndex=numericValuesLength;  | 
1130  | 0  |     if(numericValuesList==NULL) { | 
1131  | 0  |         numericValuesList=new MessagePatternDoubleList();  | 
1132  | 0  |         if(numericValuesList==NULL) { | 
1133  | 0  |             errorCode=U_MEMORY_ALLOCATION_ERROR;  | 
1134  | 0  |             return;  | 
1135  | 0  |         }  | 
1136  | 0  |     } else if(!numericValuesList->ensureCapacityForOneMore(numericValuesLength, errorCode)) { | 
1137  | 0  |         return;  | 
1138  | 0  |     } else { | 
1139  | 0  |         if(numericIndex>Part::MAX_VALUE) { | 
1140  | 0  |             errorCode=U_INDEX_OUTOFBOUNDS_ERROR;  | 
1141  | 0  |             return;  | 
1142  | 0  |         }  | 
1143  | 0  |     }  | 
1144  | 0  |     numericValuesList->a[numericValuesLength++]=numericValue;  | 
1145  | 0  |     addPart(UMSGPAT_PART_TYPE_ARG_DOUBLE, start, length, numericIndex, errorCode);  | 
1146  | 0  | }  | 
1147  |  |  | 
1148  |  | void  | 
1149  | 0  | MessagePattern::setParseError(UParseError *parseError, int32_t index) { | 
1150  | 0  |     if(parseError==NULL) { | 
1151  | 0  |         return;  | 
1152  | 0  |     }  | 
1153  | 0  |     parseError->offset=index;  | 
1154  |  |  | 
1155  |  |     // Set preContext to some of msg before index.  | 
1156  |  |     // Avoid splitting a surrogate pair.  | 
1157  | 0  |     int32_t length=index;  | 
1158  | 0  |     if(length>=U_PARSE_CONTEXT_LEN) { | 
1159  | 0  |         length=U_PARSE_CONTEXT_LEN-1;  | 
1160  | 0  |         if(length>0 && U16_IS_TRAIL(msg[index-length])) { | 
1161  | 0  |             --length;  | 
1162  | 0  |         }  | 
1163  | 0  |     }  | 
1164  | 0  |     msg.extract(index-length, length, parseError->preContext);  | 
1165  | 0  |     parseError->preContext[length]=0;  | 
1166  |  |  | 
1167  |  |     // Set postContext to some of msg starting at index.  | 
1168  | 0  |     length=msg.length()-index;  | 
1169  | 0  |     if(length>=U_PARSE_CONTEXT_LEN) { | 
1170  | 0  |         length=U_PARSE_CONTEXT_LEN-1;  | 
1171  | 0  |         if(length>0 && U16_IS_LEAD(msg[index+length-1])) { | 
1172  | 0  |             --length;  | 
1173  | 0  |         }  | 
1174  | 0  |     }  | 
1175  | 0  |     msg.extract(index, length, parseError->postContext);  | 
1176  | 0  |     parseError->postContext[length]=0;  | 
1177  | 0  | }  | 
1178  |  |  | 
1179  |  | // MessageImpl ------------------------------------------------------------- ***  | 
1180  |  |  | 
1181  |  | void  | 
1182  |  | MessageImpl::appendReducedApostrophes(const UnicodeString &s, int32_t start, int32_t limit,  | 
1183  | 0  |                                       UnicodeString &sb) { | 
1184  | 0  |     int32_t doubleApos=-1;  | 
1185  | 0  |     for(;;) { | 
1186  | 0  |         int32_t i=s.indexOf(u_apos, start);  | 
1187  | 0  |         if(i<0 || i>=limit) { | 
1188  | 0  |             sb.append(s, start, limit-start);  | 
1189  | 0  |             break;  | 
1190  | 0  |         }  | 
1191  | 0  |         if(i==doubleApos) { | 
1192  |  |             // Double apostrophe at start-1 and start==i, append one.  | 
1193  | 0  |             sb.append(u_apos);  | 
1194  | 0  |             ++start;  | 
1195  | 0  |             doubleApos=-1;  | 
1196  | 0  |         } else { | 
1197  |  |             // Append text between apostrophes and skip this one.  | 
1198  | 0  |             sb.append(s, start, i-start);  | 
1199  | 0  |             doubleApos=start=i+1;  | 
1200  | 0  |         }  | 
1201  | 0  |     }  | 
1202  | 0  | }  | 
1203  |  |  | 
1204  |  | // Ported from second half of ICU4J SelectFormat.format(String).  | 
1205  |  | UnicodeString &  | 
1206  |  | MessageImpl::appendSubMessageWithoutSkipSyntax(const MessagePattern &msgPattern,  | 
1207  |  |                                                int32_t msgStart,  | 
1208  | 0  |                                                UnicodeString &result) { | 
1209  | 0  |     const UnicodeString &msgString=msgPattern.getPatternString();  | 
1210  | 0  |     int32_t prevIndex=msgPattern.getPart(msgStart).getLimit();  | 
1211  | 0  |     for(int32_t i=msgStart;;) { | 
1212  | 0  |         const MessagePattern::Part &part=msgPattern.getPart(++i);  | 
1213  | 0  |         UMessagePatternPartType type=part.getType();  | 
1214  | 0  |         int32_t index=part.getIndex();  | 
1215  | 0  |         if(type==UMSGPAT_PART_TYPE_MSG_LIMIT) { | 
1216  | 0  |             return result.append(msgString, prevIndex, index-prevIndex);  | 
1217  | 0  |         } else if(type==UMSGPAT_PART_TYPE_SKIP_SYNTAX) { | 
1218  | 0  |             result.append(msgString, prevIndex, index-prevIndex);  | 
1219  | 0  |             prevIndex=part.getLimit();  | 
1220  | 0  |         } else if(type==UMSGPAT_PART_TYPE_ARG_START) { | 
1221  | 0  |             result.append(msgString, prevIndex, index-prevIndex);  | 
1222  | 0  |             prevIndex=index;  | 
1223  | 0  |             i=msgPattern.getLimitPartIndex(i);  | 
1224  | 0  |             index=msgPattern.getPart(i).getLimit();  | 
1225  | 0  |             appendReducedApostrophes(msgString, prevIndex, index, result);  | 
1226  | 0  |             prevIndex=index;  | 
1227  | 0  |         }  | 
1228  | 0  |     }  | 
1229  | 0  | }  | 
1230  |  |  | 
1231  |  | U_NAMESPACE_END  | 
1232  |  |  | 
1233  |  | #endif  // !UCONFIG_NO_FORMATTING  |