|
1 /* |
|
2 ******************************************************************************* |
|
3 * |
|
4 * Copyright (C) 1999-2012, International Business Machines |
|
5 * Corporation and others. All Rights Reserved. |
|
6 * |
|
7 ******************************************************************************* |
|
8 * file name: umsg.cpp |
|
9 * encoding: US-ASCII |
|
10 * tab size: 8 (not used) |
|
11 * indentation:4 |
|
12 * |
|
13 * This is a C wrapper to MessageFormat C++ API. |
|
14 * |
|
15 * Change history: |
|
16 * |
|
17 * 08/5/2001 Ram Added C wrappers for C++ API. Changed implementation of old API's |
|
18 * Removed pattern parser. |
|
19 * |
|
20 */ |
|
21 |
|
22 #include "unicode/utypes.h" |
|
23 |
|
24 #if !UCONFIG_NO_FORMATTING |
|
25 |
|
26 #include "unicode/umsg.h" |
|
27 #include "unicode/ustring.h" |
|
28 #include "unicode/fmtable.h" |
|
29 #include "unicode/msgfmt.h" |
|
30 #include "unicode/unistr.h" |
|
31 #include "cpputils.h" |
|
32 #include "uassert.h" |
|
33 #include "ustr_imp.h" |
|
34 |
|
35 U_NAMESPACE_BEGIN |
|
36 /** |
|
37 * This class isolates our access to private internal methods of |
|
38 * MessageFormat. It is never instantiated; it exists only for C++ |
|
39 * access management. |
|
40 */ |
|
41 class MessageFormatAdapter { |
|
42 public: |
|
43 static const Formattable::Type* getArgTypeList(const MessageFormat& m, |
|
44 int32_t& count); |
|
45 static UBool hasArgTypeConflicts(const MessageFormat& m) { |
|
46 return m.hasArgTypeConflicts; |
|
47 } |
|
48 }; |
|
49 const Formattable::Type* |
|
50 MessageFormatAdapter::getArgTypeList(const MessageFormat& m, |
|
51 int32_t& count) { |
|
52 return m.getArgTypeList(count); |
|
53 } |
|
54 U_NAMESPACE_END |
|
55 |
|
56 U_NAMESPACE_USE |
|
57 |
|
58 U_CAPI int32_t |
|
59 u_formatMessage(const char *locale, |
|
60 const UChar *pattern, |
|
61 int32_t patternLength, |
|
62 UChar *result, |
|
63 int32_t resultLength, |
|
64 UErrorCode *status, |
|
65 ...) |
|
66 { |
|
67 va_list ap; |
|
68 int32_t actLen; |
|
69 //argument checking defered to subsequent method calls |
|
70 // start vararg processing |
|
71 va_start(ap, status); |
|
72 |
|
73 actLen = u_vformatMessage(locale,pattern,patternLength,result,resultLength,ap,status); |
|
74 // end vararg processing |
|
75 va_end(ap); |
|
76 |
|
77 return actLen; |
|
78 } |
|
79 |
|
80 U_CAPI int32_t U_EXPORT2 |
|
81 u_vformatMessage( const char *locale, |
|
82 const UChar *pattern, |
|
83 int32_t patternLength, |
|
84 UChar *result, |
|
85 int32_t resultLength, |
|
86 va_list ap, |
|
87 UErrorCode *status) |
|
88 |
|
89 { |
|
90 //argument checking defered to subsequent method calls |
|
91 UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,NULL,status); |
|
92 int32_t retVal = umsg_vformat(fmt,result,resultLength,ap,status); |
|
93 umsg_close(fmt); |
|
94 return retVal; |
|
95 } |
|
96 |
|
97 U_CAPI int32_t |
|
98 u_formatMessageWithError(const char *locale, |
|
99 const UChar *pattern, |
|
100 int32_t patternLength, |
|
101 UChar *result, |
|
102 int32_t resultLength, |
|
103 UParseError *parseError, |
|
104 UErrorCode *status, |
|
105 ...) |
|
106 { |
|
107 va_list ap; |
|
108 int32_t actLen; |
|
109 //argument checking defered to subsequent method calls |
|
110 // start vararg processing |
|
111 va_start(ap, status); |
|
112 |
|
113 actLen = u_vformatMessageWithError(locale,pattern,patternLength,result,resultLength,parseError,ap,status); |
|
114 |
|
115 // end vararg processing |
|
116 va_end(ap); |
|
117 return actLen; |
|
118 } |
|
119 |
|
120 U_CAPI int32_t U_EXPORT2 |
|
121 u_vformatMessageWithError( const char *locale, |
|
122 const UChar *pattern, |
|
123 int32_t patternLength, |
|
124 UChar *result, |
|
125 int32_t resultLength, |
|
126 UParseError *parseError, |
|
127 va_list ap, |
|
128 UErrorCode *status) |
|
129 |
|
130 { |
|
131 //argument checking defered to subsequent method calls |
|
132 UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,parseError,status); |
|
133 int32_t retVal = umsg_vformat(fmt,result,resultLength,ap,status); |
|
134 umsg_close(fmt); |
|
135 return retVal; |
|
136 } |
|
137 |
|
138 |
|
139 // For parse, do the reverse of format: |
|
140 // 1. Call through to the C++ APIs |
|
141 // 2. Just assume the user passed in enough arguments. |
|
142 // 3. Iterate through each formattable returned, and assign to the arguments |
|
143 U_CAPI void |
|
144 u_parseMessage( const char *locale, |
|
145 const UChar *pattern, |
|
146 int32_t patternLength, |
|
147 const UChar *source, |
|
148 int32_t sourceLength, |
|
149 UErrorCode *status, |
|
150 ...) |
|
151 { |
|
152 va_list ap; |
|
153 //argument checking defered to subsequent method calls |
|
154 |
|
155 // start vararg processing |
|
156 va_start(ap, status); |
|
157 |
|
158 u_vparseMessage(locale,pattern,patternLength,source,sourceLength,ap,status); |
|
159 // end vararg processing |
|
160 va_end(ap); |
|
161 } |
|
162 |
|
163 U_CAPI void U_EXPORT2 |
|
164 u_vparseMessage(const char *locale, |
|
165 const UChar *pattern, |
|
166 int32_t patternLength, |
|
167 const UChar *source, |
|
168 int32_t sourceLength, |
|
169 va_list ap, |
|
170 UErrorCode *status) |
|
171 { |
|
172 //argument checking defered to subsequent method calls |
|
173 UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,NULL,status); |
|
174 int32_t count = 0; |
|
175 umsg_vparse(fmt,source,sourceLength,&count,ap,status); |
|
176 umsg_close(fmt); |
|
177 } |
|
178 |
|
179 U_CAPI void |
|
180 u_parseMessageWithError(const char *locale, |
|
181 const UChar *pattern, |
|
182 int32_t patternLength, |
|
183 const UChar *source, |
|
184 int32_t sourceLength, |
|
185 UParseError *error, |
|
186 UErrorCode *status, |
|
187 ...) |
|
188 { |
|
189 va_list ap; |
|
190 |
|
191 //argument checking defered to subsequent method calls |
|
192 |
|
193 // start vararg processing |
|
194 va_start(ap, status); |
|
195 |
|
196 u_vparseMessageWithError(locale,pattern,patternLength,source,sourceLength,ap,error,status); |
|
197 // end vararg processing |
|
198 va_end(ap); |
|
199 } |
|
200 U_CAPI void U_EXPORT2 |
|
201 u_vparseMessageWithError(const char *locale, |
|
202 const UChar *pattern, |
|
203 int32_t patternLength, |
|
204 const UChar *source, |
|
205 int32_t sourceLength, |
|
206 va_list ap, |
|
207 UParseError *error, |
|
208 UErrorCode* status) |
|
209 { |
|
210 //argument checking defered to subsequent method calls |
|
211 UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,error,status); |
|
212 int32_t count = 0; |
|
213 umsg_vparse(fmt,source,sourceLength,&count,ap,status); |
|
214 umsg_close(fmt); |
|
215 } |
|
216 ////////////////////////////////////////////////////////////////////////////////// |
|
217 // |
|
218 // Message format C API |
|
219 // |
|
220 ///////////////////////////////////////////////////////////////////////////////// |
|
221 |
|
222 |
|
223 U_CAPI UMessageFormat* U_EXPORT2 |
|
224 umsg_open( const UChar *pattern, |
|
225 int32_t patternLength, |
|
226 const char *locale, |
|
227 UParseError *parseError, |
|
228 UErrorCode *status) |
|
229 { |
|
230 //check arguments |
|
231 if(status==NULL || U_FAILURE(*status)) |
|
232 { |
|
233 return 0; |
|
234 } |
|
235 if(pattern==NULL||patternLength<-1){ |
|
236 *status=U_ILLEGAL_ARGUMENT_ERROR; |
|
237 return 0; |
|
238 } |
|
239 |
|
240 UParseError tErr; |
|
241 if(parseError==NULL) |
|
242 { |
|
243 parseError = &tErr; |
|
244 } |
|
245 |
|
246 int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength); |
|
247 UnicodeString patString(patternLength == -1, pattern, len); |
|
248 |
|
249 MessageFormat* retVal = new MessageFormat(patString,Locale(locale),*parseError,*status); |
|
250 if(retVal == NULL) { |
|
251 *status = U_MEMORY_ALLOCATION_ERROR; |
|
252 return NULL; |
|
253 } |
|
254 if (U_SUCCESS(*status) && MessageFormatAdapter::hasArgTypeConflicts(*retVal)) { |
|
255 *status = U_ARGUMENT_TYPE_MISMATCH; |
|
256 } |
|
257 return (UMessageFormat*)retVal; |
|
258 } |
|
259 |
|
260 U_CAPI void U_EXPORT2 |
|
261 umsg_close(UMessageFormat* format) |
|
262 { |
|
263 //check arguments |
|
264 if(format==NULL){ |
|
265 return; |
|
266 } |
|
267 delete (MessageFormat*) format; |
|
268 } |
|
269 |
|
270 U_CAPI UMessageFormat U_EXPORT2 |
|
271 umsg_clone(const UMessageFormat *fmt, |
|
272 UErrorCode *status) |
|
273 { |
|
274 //check arguments |
|
275 if(status==NULL || U_FAILURE(*status)){ |
|
276 return NULL; |
|
277 } |
|
278 if(fmt==NULL){ |
|
279 *status = U_ILLEGAL_ARGUMENT_ERROR; |
|
280 return NULL; |
|
281 } |
|
282 UMessageFormat retVal = (UMessageFormat)((MessageFormat*)fmt)->clone(); |
|
283 if(retVal == 0) { |
|
284 *status = U_MEMORY_ALLOCATION_ERROR; |
|
285 return 0; |
|
286 } |
|
287 return retVal; |
|
288 } |
|
289 |
|
290 U_CAPI void U_EXPORT2 |
|
291 umsg_setLocale(UMessageFormat *fmt, const char* locale) |
|
292 { |
|
293 //check arguments |
|
294 if(fmt==NULL){ |
|
295 return; |
|
296 } |
|
297 ((MessageFormat*)fmt)->setLocale(Locale(locale)); |
|
298 } |
|
299 |
|
300 U_CAPI const char* U_EXPORT2 |
|
301 umsg_getLocale(const UMessageFormat *fmt) |
|
302 { |
|
303 //check arguments |
|
304 if(fmt==NULL){ |
|
305 return ""; |
|
306 } |
|
307 return ((const MessageFormat*)fmt)->getLocale().getName(); |
|
308 } |
|
309 |
|
310 U_CAPI void U_EXPORT2 |
|
311 umsg_applyPattern(UMessageFormat *fmt, |
|
312 const UChar* pattern, |
|
313 int32_t patternLength, |
|
314 UParseError* parseError, |
|
315 UErrorCode* status) |
|
316 { |
|
317 //check arguments |
|
318 UParseError tErr; |
|
319 if(status ==NULL||U_FAILURE(*status)){ |
|
320 return ; |
|
321 } |
|
322 if(fmt==NULL||pattern==NULL||patternLength<-1){ |
|
323 *status=U_ILLEGAL_ARGUMENT_ERROR; |
|
324 return ; |
|
325 } |
|
326 |
|
327 if(parseError==NULL){ |
|
328 parseError = &tErr; |
|
329 } |
|
330 if(patternLength<-1){ |
|
331 patternLength=u_strlen(pattern); |
|
332 } |
|
333 |
|
334 ((MessageFormat*)fmt)->applyPattern(UnicodeString(pattern,patternLength),*parseError,*status); |
|
335 } |
|
336 |
|
337 U_CAPI int32_t U_EXPORT2 |
|
338 umsg_toPattern(const UMessageFormat *fmt, |
|
339 UChar* result, |
|
340 int32_t resultLength, |
|
341 UErrorCode* status) |
|
342 { |
|
343 //check arguments |
|
344 if(status ==NULL||U_FAILURE(*status)){ |
|
345 return -1; |
|
346 } |
|
347 if(fmt==NULL||resultLength<0 || (resultLength>0 && result==0)){ |
|
348 *status=U_ILLEGAL_ARGUMENT_ERROR; |
|
349 return -1; |
|
350 } |
|
351 |
|
352 |
|
353 UnicodeString res; |
|
354 if(!(result==NULL && resultLength==0)) { |
|
355 // NULL destination for pure preflighting: empty dummy string |
|
356 // otherwise, alias the destination buffer |
|
357 res.setTo(result, 0, resultLength); |
|
358 } |
|
359 ((const MessageFormat*)fmt)->toPattern(res); |
|
360 return res.extract(result, resultLength, *status); |
|
361 } |
|
362 |
|
363 U_CAPI int32_t |
|
364 umsg_format( const UMessageFormat *fmt, |
|
365 UChar *result, |
|
366 int32_t resultLength, |
|
367 UErrorCode *status, |
|
368 ...) |
|
369 { |
|
370 va_list ap; |
|
371 int32_t actLen; |
|
372 //argument checking defered to last method call umsg_vformat which |
|
373 //saves time when arguments are valid and we dont care when arguments are not |
|
374 //since we return an error anyway |
|
375 |
|
376 |
|
377 // start vararg processing |
|
378 va_start(ap, status); |
|
379 |
|
380 actLen = umsg_vformat(fmt,result,resultLength,ap,status); |
|
381 |
|
382 // end vararg processing |
|
383 va_end(ap); |
|
384 |
|
385 return actLen; |
|
386 } |
|
387 |
|
388 U_CAPI int32_t U_EXPORT2 |
|
389 umsg_vformat( const UMessageFormat *fmt, |
|
390 UChar *result, |
|
391 int32_t resultLength, |
|
392 va_list ap, |
|
393 UErrorCode *status) |
|
394 { |
|
395 //check arguments |
|
396 if(status==0 || U_FAILURE(*status)) |
|
397 { |
|
398 return -1; |
|
399 } |
|
400 if(fmt==NULL||resultLength<0 || (resultLength>0 && result==0)) { |
|
401 *status=U_ILLEGAL_ARGUMENT_ERROR; |
|
402 return -1; |
|
403 } |
|
404 |
|
405 int32_t count =0; |
|
406 const Formattable::Type* argTypes = |
|
407 MessageFormatAdapter::getArgTypeList(*(const MessageFormat*)fmt, count); |
|
408 // Allocate at least one element. Allocating an array of length |
|
409 // zero causes problems on some platforms (e.g. Win32). |
|
410 Formattable* args = new Formattable[count ? count : 1]; |
|
411 |
|
412 // iterate through the vararg list, and get the arguments out |
|
413 for(int32_t i = 0; i < count; ++i) { |
|
414 |
|
415 UChar *stringVal; |
|
416 double tDouble=0; |
|
417 int32_t tInt =0; |
|
418 int64_t tInt64 = 0; |
|
419 UDate tempDate = 0; |
|
420 switch(argTypes[i]) { |
|
421 case Formattable::kDate: |
|
422 tempDate = va_arg(ap, UDate); |
|
423 args[i].setDate(tempDate); |
|
424 break; |
|
425 |
|
426 case Formattable::kDouble: |
|
427 tDouble =va_arg(ap, double); |
|
428 args[i].setDouble(tDouble); |
|
429 break; |
|
430 |
|
431 case Formattable::kLong: |
|
432 tInt = va_arg(ap, int32_t); |
|
433 args[i].setLong(tInt); |
|
434 break; |
|
435 |
|
436 case Formattable::kInt64: |
|
437 tInt64 = va_arg(ap, int64_t); |
|
438 args[i].setInt64(tInt64); |
|
439 break; |
|
440 |
|
441 case Formattable::kString: |
|
442 // For some reason, a temporary is needed |
|
443 stringVal = va_arg(ap, UChar*); |
|
444 if(stringVal){ |
|
445 args[i].setString(UnicodeString(stringVal)); |
|
446 }else{ |
|
447 *status=U_ILLEGAL_ARGUMENT_ERROR; |
|
448 } |
|
449 break; |
|
450 |
|
451 case Formattable::kArray: |
|
452 // throw away this argument |
|
453 // this is highly platform-dependent, and probably won't work |
|
454 // so, if you try to skip arguments in the list (and not use them) |
|
455 // you'll probably crash |
|
456 va_arg(ap, int); |
|
457 break; |
|
458 |
|
459 case Formattable::kObject: |
|
460 // Unused argument number. Read and ignore a pointer argument. |
|
461 va_arg(ap, void*); |
|
462 break; |
|
463 |
|
464 default: |
|
465 // Unknown/unsupported argument type. |
|
466 U_ASSERT(FALSE); |
|
467 *status=U_ILLEGAL_ARGUMENT_ERROR; |
|
468 break; |
|
469 } |
|
470 } |
|
471 UnicodeString resultStr; |
|
472 FieldPosition fieldPosition(0); |
|
473 |
|
474 /* format the message */ |
|
475 ((const MessageFormat*)fmt)->format(args,count,resultStr,fieldPosition,*status); |
|
476 |
|
477 delete[] args; |
|
478 |
|
479 if(U_FAILURE(*status)){ |
|
480 return -1; |
|
481 } |
|
482 |
|
483 return resultStr.extract(result, resultLength, *status); |
|
484 } |
|
485 |
|
486 U_CAPI void |
|
487 umsg_parse( const UMessageFormat *fmt, |
|
488 const UChar *source, |
|
489 int32_t sourceLength, |
|
490 int32_t *count, |
|
491 UErrorCode *status, |
|
492 ...) |
|
493 { |
|
494 va_list ap; |
|
495 //argument checking defered to last method call umsg_vparse which |
|
496 //saves time when arguments are valid and we dont care when arguments are not |
|
497 //since we return an error anyway |
|
498 |
|
499 // start vararg processing |
|
500 va_start(ap, status); |
|
501 |
|
502 umsg_vparse(fmt,source,sourceLength,count,ap,status); |
|
503 |
|
504 // end vararg processing |
|
505 va_end(ap); |
|
506 } |
|
507 |
|
508 U_CAPI void U_EXPORT2 |
|
509 umsg_vparse(const UMessageFormat *fmt, |
|
510 const UChar *source, |
|
511 int32_t sourceLength, |
|
512 int32_t *count, |
|
513 va_list ap, |
|
514 UErrorCode *status) |
|
515 { |
|
516 //check arguments |
|
517 if(status==NULL||U_FAILURE(*status)) |
|
518 { |
|
519 return; |
|
520 } |
|
521 if(fmt==NULL||source==NULL || sourceLength<-1 || count==NULL){ |
|
522 *status=U_ILLEGAL_ARGUMENT_ERROR; |
|
523 return; |
|
524 } |
|
525 if(sourceLength==-1){ |
|
526 sourceLength=u_strlen(source); |
|
527 } |
|
528 |
|
529 UnicodeString srcString(source,sourceLength); |
|
530 Formattable *args = ((const MessageFormat*)fmt)->parse(srcString,*count,*status); |
|
531 UDate *aDate; |
|
532 double *aDouble; |
|
533 UChar *aString; |
|
534 int32_t* aInt; |
|
535 int64_t* aInt64; |
|
536 UnicodeString temp; |
|
537 int len =0; |
|
538 // assign formattables to varargs |
|
539 for(int32_t i = 0; i < *count; i++) { |
|
540 switch(args[i].getType()) { |
|
541 |
|
542 case Formattable::kDate: |
|
543 aDate = va_arg(ap, UDate*); |
|
544 if(aDate){ |
|
545 *aDate = args[i].getDate(); |
|
546 }else{ |
|
547 *status=U_ILLEGAL_ARGUMENT_ERROR; |
|
548 } |
|
549 break; |
|
550 |
|
551 case Formattable::kDouble: |
|
552 aDouble = va_arg(ap, double*); |
|
553 if(aDouble){ |
|
554 *aDouble = args[i].getDouble(); |
|
555 }else{ |
|
556 *status=U_ILLEGAL_ARGUMENT_ERROR; |
|
557 } |
|
558 break; |
|
559 |
|
560 case Formattable::kLong: |
|
561 aInt = va_arg(ap, int32_t*); |
|
562 if(aInt){ |
|
563 *aInt = (int32_t) args[i].getLong(); |
|
564 }else{ |
|
565 *status=U_ILLEGAL_ARGUMENT_ERROR; |
|
566 } |
|
567 break; |
|
568 |
|
569 case Formattable::kInt64: |
|
570 aInt64 = va_arg(ap, int64_t*); |
|
571 if(aInt64){ |
|
572 *aInt64 = args[i].getInt64(); |
|
573 }else{ |
|
574 *status=U_ILLEGAL_ARGUMENT_ERROR; |
|
575 } |
|
576 break; |
|
577 |
|
578 case Formattable::kString: |
|
579 aString = va_arg(ap, UChar*); |
|
580 if(aString){ |
|
581 args[i].getString(temp); |
|
582 len = temp.length(); |
|
583 temp.extract(0,len,aString); |
|
584 aString[len]=0; |
|
585 }else{ |
|
586 *status= U_ILLEGAL_ARGUMENT_ERROR; |
|
587 } |
|
588 break; |
|
589 |
|
590 case Formattable::kObject: |
|
591 // This will never happen because MessageFormat doesn't |
|
592 // support kObject. When MessageFormat is changed to |
|
593 // understand MeasureFormats, modify this code to do the |
|
594 // right thing. [alan] |
|
595 U_ASSERT(FALSE); |
|
596 break; |
|
597 |
|
598 // better not happen! |
|
599 case Formattable::kArray: |
|
600 U_ASSERT(FALSE); |
|
601 break; |
|
602 } |
|
603 } |
|
604 |
|
605 // clean up |
|
606 delete [] args; |
|
607 } |
|
608 |
|
609 #define SINGLE_QUOTE ((UChar)0x0027) |
|
610 #define CURLY_BRACE_LEFT ((UChar)0x007B) |
|
611 #define CURLY_BRACE_RIGHT ((UChar)0x007D) |
|
612 |
|
613 #define STATE_INITIAL 0 |
|
614 #define STATE_SINGLE_QUOTE 1 |
|
615 #define STATE_IN_QUOTE 2 |
|
616 #define STATE_MSG_ELEMENT 3 |
|
617 |
|
618 #define MAppend(c) if (len < destCapacity) dest[len++] = c; else len++ |
|
619 |
|
620 int32_t umsg_autoQuoteApostrophe(const UChar* pattern, |
|
621 int32_t patternLength, |
|
622 UChar* dest, |
|
623 int32_t destCapacity, |
|
624 UErrorCode* ec) |
|
625 { |
|
626 int32_t state = STATE_INITIAL; |
|
627 int32_t braceCount = 0; |
|
628 int32_t len = 0; |
|
629 |
|
630 if (ec == NULL || U_FAILURE(*ec)) { |
|
631 return -1; |
|
632 } |
|
633 |
|
634 if (pattern == NULL || patternLength < -1 || (dest == NULL && destCapacity > 0)) { |
|
635 *ec = U_ILLEGAL_ARGUMENT_ERROR; |
|
636 return -1; |
|
637 } |
|
638 U_ASSERT(destCapacity >= 0); |
|
639 |
|
640 if (patternLength == -1) { |
|
641 patternLength = u_strlen(pattern); |
|
642 } |
|
643 |
|
644 for (int i = 0; i < patternLength; ++i) { |
|
645 UChar c = pattern[i]; |
|
646 switch (state) { |
|
647 case STATE_INITIAL: |
|
648 switch (c) { |
|
649 case SINGLE_QUOTE: |
|
650 state = STATE_SINGLE_QUOTE; |
|
651 break; |
|
652 case CURLY_BRACE_LEFT: |
|
653 state = STATE_MSG_ELEMENT; |
|
654 ++braceCount; |
|
655 break; |
|
656 } |
|
657 break; |
|
658 |
|
659 case STATE_SINGLE_QUOTE: |
|
660 switch (c) { |
|
661 case SINGLE_QUOTE: |
|
662 state = STATE_INITIAL; |
|
663 break; |
|
664 case CURLY_BRACE_LEFT: |
|
665 case CURLY_BRACE_RIGHT: |
|
666 state = STATE_IN_QUOTE; |
|
667 break; |
|
668 default: |
|
669 MAppend(SINGLE_QUOTE); |
|
670 state = STATE_INITIAL; |
|
671 break; |
|
672 } |
|
673 break; |
|
674 |
|
675 case STATE_IN_QUOTE: |
|
676 switch (c) { |
|
677 case SINGLE_QUOTE: |
|
678 state = STATE_INITIAL; |
|
679 break; |
|
680 } |
|
681 break; |
|
682 |
|
683 case STATE_MSG_ELEMENT: |
|
684 switch (c) { |
|
685 case CURLY_BRACE_LEFT: |
|
686 ++braceCount; |
|
687 break; |
|
688 case CURLY_BRACE_RIGHT: |
|
689 if (--braceCount == 0) { |
|
690 state = STATE_INITIAL; |
|
691 } |
|
692 break; |
|
693 } |
|
694 break; |
|
695 |
|
696 default: // Never happens. |
|
697 break; |
|
698 } |
|
699 |
|
700 U_ASSERT(len >= 0); |
|
701 MAppend(c); |
|
702 } |
|
703 |
|
704 // End of scan |
|
705 if (state == STATE_SINGLE_QUOTE || state == STATE_IN_QUOTE) { |
|
706 MAppend(SINGLE_QUOTE); |
|
707 } |
|
708 |
|
709 return u_terminateUChars(dest, destCapacity, len, ec); |
|
710 } |
|
711 |
|
712 #endif /* #if !UCONFIG_NO_FORMATTING */ |