Line data Source code
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 0 : class MessagePatternList : public UMemory {
92 : public:
93 0 : 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 : }
102 0 : return TRUE;
103 : }
104 :
105 : MaybeStackArray<T, stackCapacity> a;
106 : };
107 :
108 : template<typename T, int32_t stackCapacity>
109 : void
110 0 : MessagePatternList<T, stackCapacity>::copyFrom(
111 : const MessagePatternList<T, stackCapacity> &other,
112 : int32_t length,
113 : 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 : }
119 0 : uprv_memcpy(a.getAlias(), other.a.getAlias(), (size_t)length*sizeof(T));
120 : }
121 : }
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 : }
129 0 : if(a.getCapacity()>oldLength || a.resize(2*oldLength, oldLength)!=NULL) {
130 0 : return TRUE;
131 : }
132 0 : errorCode=U_MEMORY_ALLOCATION_ERROR;
133 0 : return FALSE;
134 : }
135 :
136 : // MessagePatternList specializations -------------------------------------- ***
137 :
138 0 : class MessagePatternDoubleList : public MessagePatternList<double, 8> {
139 : };
140 :
141 0 : class MessagePatternPartsList : public MessagePatternList<MessagePattern::Part, 32> {
142 : };
143 :
144 : // MessagePattern constructors etc. ---------------------------------------- ***
145 :
146 0 : MessagePattern::MessagePattern(UErrorCode &errorCode)
147 : : aposMode(UCONFIG_MSGPAT_DEFAULT_APOSTROPHE_MODE),
148 : partsList(NULL), parts(NULL), partsLength(0),
149 : numericValuesList(NULL), numericValues(NULL), numericValuesLength(0),
150 0 : hasArgNames(FALSE), hasArgNumbers(FALSE), needsAutoQuoting(FALSE) {
151 0 : init(errorCode);
152 0 : }
153 :
154 0 : MessagePattern::MessagePattern(UMessagePatternApostropheMode mode, UErrorCode &errorCode)
155 : : aposMode(mode),
156 : partsList(NULL), parts(NULL), partsLength(0),
157 : numericValuesList(NULL), numericValues(NULL), numericValuesLength(0),
158 0 : hasArgNames(FALSE), hasArgNumbers(FALSE), needsAutoQuoting(FALSE) {
159 0 : init(errorCode);
160 0 : }
161 :
162 0 : MessagePattern::MessagePattern(const UnicodeString &pattern, UParseError *parseError, UErrorCode &errorCode)
163 : : aposMode(UCONFIG_MSGPAT_DEFAULT_APOSTROPHE_MODE),
164 : partsList(NULL), parts(NULL), partsLength(0),
165 : 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 : }
170 0 : }
171 :
172 : UBool
173 0 : MessagePattern::init(UErrorCode &errorCode) {
174 0 : if(U_FAILURE(errorCode)) {
175 0 : return FALSE;
176 : }
177 0 : partsList=new MessagePatternPartsList();
178 0 : if(partsList==NULL) {
179 0 : errorCode=U_MEMORY_ALLOCATION_ERROR;
180 0 : return FALSE;
181 : }
182 0 : parts=partsList->a.getAlias();
183 0 : return TRUE;
184 : }
185 :
186 0 : MessagePattern::MessagePattern(const MessagePattern &other)
187 0 : : UObject(other), aposMode(other.aposMode), msg(other.msg),
188 : partsList(NULL), parts(NULL), partsLength(0),
189 : 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 : }
196 0 : }
197 :
198 : MessagePattern &
199 0 : MessagePattern::operator=(const MessagePattern &other) {
200 0 : if(this==&other) {
201 0 : return *this;
202 : }
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 : }
212 0 : return *this;
213 : }
214 :
215 : UBool
216 0 : MessagePattern::copyStorage(const MessagePattern &other, UErrorCode &errorCode) {
217 0 : if(U_FAILURE(errorCode)) {
218 0 : return FALSE;
219 : }
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 : }
230 0 : parts=partsList->a.getAlias();
231 : }
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 : }
237 0 : parts=partsList->a.getAlias();
238 0 : partsLength=other.partsLength;
239 : }
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 : }
247 0 : numericValues=numericValuesList->a.getAlias();
248 : }
249 0 : numericValuesList->copyFrom(
250 0 : *other.numericValuesList, other.numericValuesLength, errorCode);
251 0 : if(U_FAILURE(errorCode)) {
252 0 : return FALSE;
253 : }
254 0 : numericValues=numericValuesList->a.getAlias();
255 0 : numericValuesLength=other.numericValuesLength;
256 : }
257 0 : return TRUE;
258 : }
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 : }
274 :
275 : MessagePattern &
276 0 : MessagePattern::parseChoiceStyle(const UnicodeString &pattern,
277 : 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 : }
283 :
284 : MessagePattern &
285 0 : MessagePattern::parsePluralStyle(const UnicodeString &pattern,
286 : 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 : }
292 :
293 : MessagePattern &
294 0 : MessagePattern::parseSelectStyle(const UnicodeString &pattern,
295 : 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 : }
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 : UBool
313 0 : MessagePattern::operator==(const MessagePattern &other) const {
314 0 : if(this==&other) {
315 0 : return TRUE;
316 : }
317 : 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 : }
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 : }
332 0 : return hash;
333 : }
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 : }
340 0 : return parseArgNumber(name, 0, name.length());
341 : }
342 :
343 : UnicodeString
344 0 : MessagePattern::autoQuoteApostropheDeep() const {
345 0 : if(!needsAutoQuoting) {
346 0 : return msg;
347 : }
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 : }
356 : }
357 0 : return modified;
358 : }
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 : } else {
368 0 : return UMSGPAT_NO_NUMERIC_VALUE;
369 : }
370 : }
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 : } else {
384 0 : return 0;
385 : }
386 : }
387 :
388 : // MessagePattern::Part ---------------------------------------------------- ***
389 :
390 : UBool
391 0 : MessagePattern::Part::operator==(const Part &other) const {
392 0 : if(this==&other) {
393 0 : return TRUE;
394 : }
395 : 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 : }
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 : }
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 : }
416 0 : msg=pattern;
417 0 : hasArgNames=hasArgNumbers=FALSE;
418 0 : needsAutoQuoting=FALSE;
419 0 : partsLength=0;
420 0 : numericValuesLength=0;
421 : }
422 :
423 : void
424 0 : MessagePattern::postParse() {
425 0 : if(partsList!=NULL) {
426 0 : parts=partsList->a.getAlias();
427 : }
428 0 : if(numericValuesList!=NULL) {
429 0 : numericValues=numericValuesList->a.getAlias();
430 : }
431 0 : }
432 :
433 : int32_t
434 0 : MessagePattern::parseMessage(int32_t index, int32_t msgStartLength,
435 : int32_t nestingLevel, UMessagePatternArgType parentType,
436 : UParseError *parseError, UErrorCode &errorCode) {
437 0 : if(U_FAILURE(errorCode)) {
438 0 : return 0;
439 : }
440 0 : if(nestingLevel>Part::MAX_VALUE) {
441 0 : errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
442 0 : return 0;
443 : }
444 0 : int32_t msgStart=partsLength;
445 0 : addPart(UMSGPAT_PART_TYPE_MSG_START, index, msgStartLength, nestingLevel, errorCode);
446 0 : index+=msgStartLength;
447 : for(;;) { // while(index<msg.length()) with U_FAILURE(errorCode) check
448 0 : if(U_FAILURE(errorCode)) {
449 0 : return 0;
450 : }
451 0 : if(index>=msg.length()) {
452 0 : break;
453 : }
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 : addPart(UMSGPAT_PART_TYPE_INSERT_CHAR, index, 0,
460 0 : u_apos, errorCode); // value=char to be inserted
461 0 : needsAutoQuoting=TRUE;
462 : } 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 : ) {
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 : 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 : } else {
484 : // skip the quote-ending apostrophe
485 0 : addPart(UMSGPAT_PART_TYPE_SKIP_SYNTAX, index++, 1, 0, errorCode);
486 0 : break;
487 : }
488 : } 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 : 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 : }
497 : }
498 : } else {
499 : // Interpret the apostrophe as literal text.
500 : // Add a Part for auto-quoting.
501 : addPart(UMSGPAT_PART_TYPE_INSERT_CHAR, index, 0,
502 0 : u_apos, errorCode); // value=char to be inserted
503 0 : needsAutoQuoting=TRUE;
504 : }
505 : }
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 : } else {
524 : // continue parsing after the '}'
525 0 : return index;
526 : }
527 : } // 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 : }
534 0 : addLimitPart(msgStart, UMSGPAT_PART_TYPE_MSG_LIMIT, index, 0, nestingLevel, errorCode);
535 0 : return index;
536 : }
537 :
538 : int32_t
539 0 : MessagePattern::parseArg(int32_t index, int32_t argStartLength, int32_t nestingLevel,
540 : 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 : }
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 : }
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 : }
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 : }
572 0 : hasArgNames=TRUE;
573 0 : addPart(UMSGPAT_PART_TYPE_ARG_NAME, nameIndex, length, 0, errorCode);
574 : } 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 : }
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 : }
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 : } 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 : }
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 : }
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 : }
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 : }
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 : }
625 0 : } else if(length==13) {
626 0 : if(isSelect(typeIndex) && isOrdinal(typeIndex+6)) {
627 0 : argType=UMSGPAT_ARG_TYPE_SELECTORDINAL;
628 : }
629 : }
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 : }
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 : }
642 : } 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 : } else {
649 0 : index=parsePluralOrSelectStyle(argType, index, nestingLevel, parseError, errorCode);
650 : }
651 : }
652 : }
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 : }
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 : }
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 : }
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 : } 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 : }
691 0 : addPart(UMSGPAT_PART_TYPE_ARG_STYLE, start, length, 0, errorCode);
692 0 : return index;
693 : }
694 : } // c is part of literal text
695 : }
696 0 : setParseError(parseError, 0); // Unmatched '{' braces in message.
697 0 : errorCode=U_UNMATCHED_BRACES;
698 0 : return 0;
699 : }
700 :
701 : int32_t
702 0 : MessagePattern::parseChoiceStyle(int32_t index, int32_t nestingLevel,
703 : UParseError *parseError, UErrorCode &errorCode) {
704 0 : if(U_FAILURE(errorCode)) {
705 0 : return 0;
706 : }
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 : }
714 : 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 : }
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 : }
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 : }
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 : }
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 : }
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 : }
753 : // parseMessage(..., CHOICE) returns the index of the terminator, or msg.length().
754 0 : if(index==msg.length()) {
755 0 : return index;
756 : }
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 : }
763 0 : return index;
764 : } // else the terminator is '|'
765 0 : index=skipWhiteSpace(index+1);
766 0 : }
767 : }
768 :
769 : int32_t
770 0 : MessagePattern::parsePluralOrSelectStyle(UMessagePatternArgType argType,
771 : int32_t index, int32_t nestingLevel,
772 : UParseError *parseError, UErrorCode &errorCode) {
773 0 : if(U_FAILURE(errorCode)) {
774 0 : return 0;
775 : }
776 0 : int32_t start=index;
777 0 : UBool isEmpty=TRUE;
778 0 : UBool hasOther=FALSE;
779 : 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 : }
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 : }
796 0 : return index;
797 : }
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 : }
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 : }
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 : } 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 : }
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 : ) {
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 : }
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 : }
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 : }
848 : 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 : }
853 0 : isEmpty=FALSE;
854 0 : continue; // no message fragment after the offset
855 : } 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 : }
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 : }
866 : }
867 : }
868 0 : if(U_FAILURE(errorCode)) {
869 0 : return 0;
870 : }
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 : }
879 0 : index=parseMessage(index, 1, nestingLevel+1, argType, parseError, errorCode);
880 0 : if(U_FAILURE(errorCode)) {
881 0 : return 0;
882 : }
883 0 : isEmpty=FALSE;
884 0 : }
885 : }
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 : }
895 : int32_t number;
896 : // Defer numeric errors until we know there are only digits.
897 : UBool badNumber;
898 0 : UChar c=s.charAt(start++);
899 0 : if(c==0x30) {
900 0 : if(start==limit) {
901 0 : return 0;
902 : } else {
903 0 : number=0;
904 0 : badNumber=TRUE; // leading zero
905 : }
906 0 : } else if(0x31<=c && c<=0x39) {
907 0 : number=c-0x30;
908 0 : badNumber=FALSE;
909 : } else {
910 0 : return UMSGPAT_ARG_NAME_NOT_NUMBER;
911 : }
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 : }
918 0 : number=number*10+(c-0x30);
919 : } else {
920 0 : return UMSGPAT_ARG_NAME_NOT_NUMBER;
921 : }
922 : }
923 : // There are only ASCII digits.
924 0 : if(badNumber) {
925 0 : return UMSGPAT_ARG_NAME_NOT_VALID;
926 : } else {
927 0 : return number;
928 : }
929 : }
930 :
931 : void
932 0 : MessagePattern::parseDouble(int32_t start, int32_t limit, UBool allowInfinity,
933 : UParseError *parseError, UErrorCode &errorCode) {
934 0 : if(U_FAILURE(errorCode)) {
935 0 : return;
936 : }
937 0 : U_ASSERT(start<limit);
938 : // fake loop for easy exit and single throw statement
939 : 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 : }
950 0 : c=msg.charAt(index++);
951 0 : } else if(c==u_plus) {
952 0 : if(index==limit) {
953 0 : break; // no number
954 : }
955 0 : c=msg.charAt(index++);
956 : }
957 0 : if(c==0x221e) { // infinity
958 0 : if(allowInfinity && index==limit) {
959 0 : double infinity=uprv_getInfinity();
960 0 : addArgDoublePart(
961 : isNegative!=0 ? -infinity : infinity,
962 0 : start, limit-start, errorCode);
963 0 : return;
964 : } else {
965 : break;
966 : }
967 : }
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 : }
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 : }
979 0 : c=msg.charAt(index++);
980 : }
981 : // Let Double.parseDouble() throw a NumberFormatException.
982 : 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 : }
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 : }
992 : char *end;
993 0 : double numericValue=uprv_strtod(numberChars, &end);
994 0 : if(end!=(numberChars+length)) {
995 0 : break; // parsing error
996 : }
997 0 : addArgDoublePart(numericValue, start, length, errorCode);
998 0 : return;
999 : }
1000 0 : setParseError(parseError, start /*, limit*/); // Bad syntax for numeric value.
1001 0 : errorCode=U_PATTERN_SYNTAX_ERROR;
1002 0 : return;
1003 : }
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 : }
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 : }
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 : break;
1029 : }
1030 0 : ++index;
1031 : }
1032 0 : return index;
1033 : }
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 : }
1039 :
1040 : UBool
1041 0 : MessagePattern::isChoice(int32_t index) {
1042 : UChar c;
1043 : 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 : }
1051 :
1052 : UBool
1053 0 : MessagePattern::isPlural(int32_t index) {
1054 : UChar c;
1055 : 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 : }
1063 :
1064 : UBool
1065 0 : MessagePattern::isSelect(int32_t index) {
1066 : UChar c;
1067 : 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 : }
1075 :
1076 : UBool
1077 0 : MessagePattern::isOrdinal(int32_t index) {
1078 : UChar c;
1079 : 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 : }
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 : }
1093 :
1094 : UBool
1095 0 : MessagePattern::inTopLevelChoiceMessage(int32_t nestingLevel, UMessagePatternArgType parentType) {
1096 : return
1097 0 : nestingLevel==1 &&
1098 0 : parentType==UMSGPAT_ARG_TYPE_CHOICE &&
1099 0 : partsList->a[0].type!=UMSGPAT_PART_TYPE_MSG_START;
1100 : }
1101 :
1102 : void
1103 0 : MessagePattern::addPart(UMessagePatternPartType type, int32_t index, int32_t length,
1104 : 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 : }
1113 0 : }
1114 :
1115 : void
1116 0 : MessagePattern::addLimitPart(int32_t start,
1117 : UMessagePatternPartType type, int32_t index, int32_t length,
1118 : 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 0 : MessagePattern::addArgDoublePart(double numericValue, int32_t start, int32_t length,
1125 : UErrorCode &errorCode) {
1126 0 : if(U_FAILURE(errorCode)) {
1127 0 : return;
1128 : }
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 : }
1136 0 : } else if(!numericValuesList->ensureCapacityForOneMore(numericValuesLength, errorCode)) {
1137 0 : return;
1138 : } else {
1139 0 : if(numericIndex>Part::MAX_VALUE) {
1140 0 : errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
1141 0 : return;
1142 : }
1143 : }
1144 0 : numericValuesList->a[numericValuesLength++]=numericValue;
1145 0 : addPart(UMSGPAT_PART_TYPE_ARG_DOUBLE, start, length, numericIndex, errorCode);
1146 : }
1147 :
1148 : void
1149 0 : MessagePattern::setParseError(UParseError *parseError, int32_t index) {
1150 0 : if(parseError==NULL) {
1151 0 : return;
1152 : }
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 : }
1163 : }
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 : }
1174 : }
1175 0 : msg.extract(index, length, parseError->postContext);
1176 0 : parseError->postContext[length]=0;
1177 : }
1178 :
1179 : // MessageImpl ------------------------------------------------------------- ***
1180 :
1181 : void
1182 0 : MessageImpl::appendReducedApostrophes(const UnicodeString &s, int32_t start, int32_t limit,
1183 : UnicodeString &sb) {
1184 0 : int32_t doubleApos=-1;
1185 : 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 : }
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 : } 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 : }
1201 0 : }
1202 0 : }
1203 :
1204 : // Ported from second half of ICU4J SelectFormat.format(String).
1205 : UnicodeString &
1206 0 : MessageImpl::appendSubMessageWithoutSkipSyntax(const MessagePattern &msgPattern,
1207 : int32_t msgStart,
1208 : 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 : }
1228 0 : }
1229 : }
1230 :
1231 : U_NAMESPACE_END
1232 :
1233 : #endif // !UCONFIG_NO_FORMATTING
|