1 /*
2 *******************************************************************************
3 *
4 * Copyright (C) 1999-2011, 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);
hasArgTypeConflicts(const MessageFormat & m)45 static UBool hasArgTypeConflicts(const MessageFormat& m) {
46 return m.hasArgTypeConflicts;
47 }
48 };
49 const Formattable::Type*
getArgTypeList(const MessageFormat & m,int32_t & count)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
u_formatMessage(const char * locale,const UChar * pattern,int32_t patternLength,UChar * result,int32_t resultLength,UErrorCode * status,...)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
u_vformatMessage(const char * locale,const UChar * pattern,int32_t patternLength,UChar * result,int32_t resultLength,va_list ap,UErrorCode * status)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
u_formatMessageWithError(const char * locale,const UChar * pattern,int32_t patternLength,UChar * result,int32_t resultLength,UParseError * parseError,UErrorCode * status,...)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
u_vformatMessageWithError(const char * locale,const UChar * pattern,int32_t patternLength,UChar * result,int32_t resultLength,UParseError * parseError,va_list ap,UErrorCode * status)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
u_parseMessage(const char * locale,const UChar * pattern,int32_t patternLength,const UChar * source,int32_t sourceLength,UErrorCode * status,...)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
u_vparseMessage(const char * locale,const UChar * pattern,int32_t patternLength,const UChar * source,int32_t sourceLength,va_list ap,UErrorCode * status)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
u_parseMessageWithError(const char * locale,const UChar * pattern,int32_t patternLength,const UChar * source,int32_t sourceLength,UParseError * error,UErrorCode * status,...)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
u_vparseMessageWithError(const char * locale,const UChar * pattern,int32_t patternLength,const UChar * source,int32_t sourceLength,va_list ap,UParseError * error,UErrorCode * status)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
umsg_open(const UChar * pattern,int32_t patternLength,const char * locale,UParseError * parseError,UErrorCode * status)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
umsg_close(UMessageFormat * format)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
umsg_clone(const UMessageFormat * fmt,UErrorCode * status)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
umsg_setLocale(UMessageFormat * fmt,const char * locale)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
umsg_getLocale(const UMessageFormat * fmt)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
umsg_applyPattern(UMessageFormat * fmt,const UChar * pattern,int32_t patternLength,UParseError * parseError,UErrorCode * status)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
umsg_toPattern(const UMessageFormat * fmt,UChar * result,int32_t resultLength,UErrorCode * status)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
umsg_format(const UMessageFormat * fmt,UChar * result,int32_t resultLength,UErrorCode * status,...)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
umsg_vformat(const UMessageFormat * fmt,UChar * result,int32_t resultLength,va_list ap,UErrorCode * status)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(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 default:
461 // This will never happen because MessageFormat doesn't
462 // support kObject. When MessageFormat is changed to
463 // understand MeasureFormats, modify this code to do the
464 // right thing. [alan]
465 U_ASSERT(FALSE);
466 *status=U_ILLEGAL_ARGUMENT_ERROR;
467 break;
468 }
469 }
470 UnicodeString resultStr;
471 FieldPosition fieldPosition(0);
472
473 /* format the message */
474 ((const MessageFormat*)fmt)->format(args,count,resultStr,fieldPosition,*status);
475
476 delete[] args;
477
478 if(U_FAILURE(*status)){
479 return -1;
480 }
481
482 return resultStr.extract(result, resultLength, *status);
483 }
484
485 U_CAPI void
umsg_parse(const UMessageFormat * fmt,const UChar * source,int32_t sourceLength,int32_t * count,UErrorCode * status,...)486 umsg_parse( const UMessageFormat *fmt,
487 const UChar *source,
488 int32_t sourceLength,
489 int32_t *count,
490 UErrorCode *status,
491 ...)
492 {
493 va_list ap;
494 //argument checking defered to last method call umsg_vparse which
495 //saves time when arguments are valid and we dont care when arguments are not
496 //since we return an error anyway
497
498 // start vararg processing
499 va_start(ap, status);
500
501 umsg_vparse(fmt,source,sourceLength,count,ap,status);
502
503 // end vararg processing
504 va_end(ap);
505 }
506
507 U_CAPI void U_EXPORT2
umsg_vparse(const UMessageFormat * fmt,const UChar * source,int32_t sourceLength,int32_t * count,va_list ap,UErrorCode * status)508 umsg_vparse(const UMessageFormat *fmt,
509 const UChar *source,
510 int32_t sourceLength,
511 int32_t *count,
512 va_list ap,
513 UErrorCode *status)
514 {
515 //check arguments
516 if(status==NULL||U_FAILURE(*status))
517 {
518 return;
519 }
520 if(fmt==NULL||source==NULL || sourceLength<-1 || count==NULL){
521 *status=U_ILLEGAL_ARGUMENT_ERROR;
522 return;
523 }
524 if(sourceLength==-1){
525 sourceLength=u_strlen(source);
526 }
527
528 UnicodeString srcString(source,sourceLength);
529 Formattable *args = ((const MessageFormat*)fmt)->parse(source,*count,*status);
530 UDate *aDate;
531 double *aDouble;
532 UChar *aString;
533 int32_t* aInt;
534 int64_t* aInt64;
535 UnicodeString temp;
536 int len =0;
537 // assign formattables to varargs
538 for(int32_t i = 0; i < *count; i++) {
539 switch(args[i].getType()) {
540
541 case Formattable::kDate:
542 aDate = va_arg(ap, UDate*);
543 if(aDate){
544 *aDate = args[i].getDate();
545 }else{
546 *status=U_ILLEGAL_ARGUMENT_ERROR;
547 }
548 break;
549
550 case Formattable::kDouble:
551 aDouble = va_arg(ap, double*);
552 if(aDouble){
553 *aDouble = args[i].getDouble();
554 }else{
555 *status=U_ILLEGAL_ARGUMENT_ERROR;
556 }
557 break;
558
559 case Formattable::kLong:
560 aInt = va_arg(ap, int32_t*);
561 if(aInt){
562 *aInt = (int32_t) args[i].getLong();
563 }else{
564 *status=U_ILLEGAL_ARGUMENT_ERROR;
565 }
566 break;
567
568 case Formattable::kInt64:
569 aInt64 = va_arg(ap, int64_t*);
570 if(aInt64){
571 *aInt64 = args[i].getInt64();
572 }else{
573 *status=U_ILLEGAL_ARGUMENT_ERROR;
574 }
575 break;
576
577 case Formattable::kString:
578 aString = va_arg(ap, UChar*);
579 if(aString){
580 args[i].getString(temp);
581 len = temp.length();
582 temp.extract(0,len,aString);
583 aString[len]=0;
584 }else{
585 *status= U_ILLEGAL_ARGUMENT_ERROR;
586 }
587 break;
588
589 case Formattable::kObject:
590 // This will never happen because MessageFormat doesn't
591 // support kObject. When MessageFormat is changed to
592 // understand MeasureFormats, modify this code to do the
593 // right thing. [alan]
594 U_ASSERT(FALSE);
595 break;
596
597 // better not happen!
598 case Formattable::kArray:
599 U_ASSERT(FALSE);
600 break;
601 }
602 }
603
604 // clean up
605 delete [] args;
606 }
607
608 #define SINGLE_QUOTE ((UChar)0x0027)
609 #define CURLY_BRACE_LEFT ((UChar)0x007B)
610 #define CURLY_BRACE_RIGHT ((UChar)0x007D)
611
612 #define STATE_INITIAL 0
613 #define STATE_SINGLE_QUOTE 1
614 #define STATE_IN_QUOTE 2
615 #define STATE_MSG_ELEMENT 3
616
617 #define MAppend(c) if (len < destCapacity) dest[len++] = c; else len++
618
umsg_autoQuoteApostrophe(const UChar * pattern,int32_t patternLength,UChar * dest,int32_t destCapacity,UErrorCode * ec)619 int32_t umsg_autoQuoteApostrophe(const UChar* pattern,
620 int32_t patternLength,
621 UChar* dest,
622 int32_t destCapacity,
623 UErrorCode* ec)
624 {
625 int32_t state = STATE_INITIAL;
626 int32_t braceCount = 0;
627 int32_t len = 0;
628
629 if (ec == NULL || U_FAILURE(*ec)) {
630 return -1;
631 }
632
633 if (pattern == NULL || patternLength < -1 || (dest == NULL && destCapacity > 0)) {
634 *ec = U_ILLEGAL_ARGUMENT_ERROR;
635 return -1;
636 }
637
638 if (patternLength == -1) {
639 patternLength = u_strlen(pattern);
640 }
641
642 for (int i = 0; i < patternLength; ++i) {
643 UChar c = pattern[i];
644 switch (state) {
645 case STATE_INITIAL:
646 switch (c) {
647 case SINGLE_QUOTE:
648 state = STATE_SINGLE_QUOTE;
649 break;
650 case CURLY_BRACE_LEFT:
651 state = STATE_MSG_ELEMENT;
652 ++braceCount;
653 break;
654 }
655 break;
656
657 case STATE_SINGLE_QUOTE:
658 switch (c) {
659 case SINGLE_QUOTE:
660 state = STATE_INITIAL;
661 break;
662 case CURLY_BRACE_LEFT:
663 case CURLY_BRACE_RIGHT:
664 state = STATE_IN_QUOTE;
665 break;
666 default:
667 MAppend(SINGLE_QUOTE);
668 state = STATE_INITIAL;
669 break;
670 }
671 break;
672
673 case STATE_IN_QUOTE:
674 switch (c) {
675 case SINGLE_QUOTE:
676 state = STATE_INITIAL;
677 break;
678 }
679 break;
680
681 case STATE_MSG_ELEMENT:
682 switch (c) {
683 case CURLY_BRACE_LEFT:
684 ++braceCount;
685 break;
686 case CURLY_BRACE_RIGHT:
687 if (--braceCount == 0) {
688 state = STATE_INITIAL;
689 }
690 break;
691 }
692 break;
693
694 default: // Never happens.
695 break;
696 }
697
698 MAppend(c);
699 }
700
701 // End of scan
702 if (state == STATE_SINGLE_QUOTE || state == STATE_IN_QUOTE) {
703 MAppend(SINGLE_QUOTE);
704 }
705
706 return u_terminateUChars(dest, destCapacity, len, ec);
707 }
708
709 #endif /* #if !UCONFIG_NO_FORMATTING */
710