2 *******************************************************************************
4 * Copyright (C) 1999-2012, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
10 * tab size: 8 (not used)
13 * This is a C wrapper to MessageFormat C++ API.
17 * 08/5/2001 Ram Added C wrappers for C++ API. Changed implementation of old API's
18 * Removed pattern parser.
22 #include "unicode/utypes.h"
24 #if !UCONFIG_NO_FORMATTING
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"
37 * This class isolates our access to private internal methods of
38 * MessageFormat. It is never instantiated; it exists only for C++
41 class MessageFormatAdapter
{
43 static const Formattable::Type
* getArgTypeList(const MessageFormat
& m
,
45 static UBool
hasArgTypeConflicts(const MessageFormat
& m
) {
46 return m
.hasArgTypeConflicts
;
49 const Formattable::Type
*
50 MessageFormatAdapter::getArgTypeList(const MessageFormat
& m
,
52 return m
.getArgTypeList(count
);
59 u_formatMessage(const char *locale
,
61 int32_t patternLength
,
69 //argument checking defered to subsequent method calls
70 // start vararg processing
73 actLen
= u_vformatMessage(locale
,pattern
,patternLength
,result
,resultLength
,ap
,status
);
74 // end vararg processing
80 U_CAPI
int32_t U_EXPORT2
81 u_vformatMessage( const char *locale
,
83 int32_t patternLength
,
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
);
98 u_formatMessageWithError(const char *locale
,
100 int32_t patternLength
,
102 int32_t resultLength
,
103 UParseError
*parseError
,
109 //argument checking defered to subsequent method calls
110 // start vararg processing
111 va_start(ap
, status
);
113 actLen
= u_vformatMessageWithError(locale
,pattern
,patternLength
,result
,resultLength
,parseError
,ap
,status
);
115 // end vararg processing
120 U_CAPI
int32_t U_EXPORT2
121 u_vformatMessageWithError( const char *locale
,
122 const UChar
*pattern
,
123 int32_t patternLength
,
125 int32_t resultLength
,
126 UParseError
*parseError
,
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
);
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
144 u_parseMessage( const char *locale
,
145 const UChar
*pattern
,
146 int32_t patternLength
,
148 int32_t sourceLength
,
153 //argument checking defered to subsequent method calls
155 // start vararg processing
156 va_start(ap
, status
);
158 u_vparseMessage(locale
,pattern
,patternLength
,source
,sourceLength
,ap
,status
);
159 // end vararg processing
163 U_CAPI
void U_EXPORT2
164 u_vparseMessage(const char *locale
,
165 const UChar
*pattern
,
166 int32_t patternLength
,
168 int32_t sourceLength
,
172 //argument checking defered to subsequent method calls
173 UMessageFormat
*fmt
= umsg_open(pattern
,patternLength
,locale
,NULL
,status
);
175 umsg_vparse(fmt
,source
,sourceLength
,&count
,ap
,status
);
180 u_parseMessageWithError(const char *locale
,
181 const UChar
*pattern
,
182 int32_t patternLength
,
184 int32_t sourceLength
,
191 //argument checking defered to subsequent method calls
193 // start vararg processing
194 va_start(ap
, status
);
196 u_vparseMessageWithError(locale
,pattern
,patternLength
,source
,sourceLength
,ap
,error
,status
);
197 // end vararg processing
200 U_CAPI
void U_EXPORT2
201 u_vparseMessageWithError(const char *locale
,
202 const UChar
*pattern
,
203 int32_t patternLength
,
205 int32_t sourceLength
,
210 //argument checking defered to subsequent method calls
211 UMessageFormat
*fmt
= umsg_open(pattern
,patternLength
,locale
,error
,status
);
213 umsg_vparse(fmt
,source
,sourceLength
,&count
,ap
,status
);
216 //////////////////////////////////////////////////////////////////////////////////
218 // Message format C API
220 /////////////////////////////////////////////////////////////////////////////////
223 U_CAPI UMessageFormat
* U_EXPORT2
224 umsg_open( const UChar
*pattern
,
225 int32_t patternLength
,
227 UParseError
*parseError
,
231 if(status
==NULL
|| U_FAILURE(*status
))
235 if(pattern
==NULL
||patternLength
<-1){
236 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
246 int32_t len
= (patternLength
== -1 ? u_strlen(pattern
) : patternLength
);
247 UnicodeString
patString(patternLength
== -1, pattern
, len
);
249 MessageFormat
* retVal
= new MessageFormat(patString
,Locale(locale
),*parseError
,*status
);
251 *status
= U_MEMORY_ALLOCATION_ERROR
;
254 if (U_SUCCESS(*status
) && MessageFormatAdapter::hasArgTypeConflicts(*retVal
)) {
255 *status
= U_ARGUMENT_TYPE_MISMATCH
;
257 return (UMessageFormat
*)retVal
;
260 U_CAPI
void U_EXPORT2
261 umsg_close(UMessageFormat
* format
)
267 delete (MessageFormat
*) format
;
270 U_CAPI UMessageFormat U_EXPORT2
271 umsg_clone(const UMessageFormat
*fmt
,
275 if(status
==NULL
|| U_FAILURE(*status
)){
279 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
282 UMessageFormat retVal
= (UMessageFormat
)((MessageFormat
*)fmt
)->clone();
284 *status
= U_MEMORY_ALLOCATION_ERROR
;
290 U_CAPI
void U_EXPORT2
291 umsg_setLocale(UMessageFormat
*fmt
, const char* locale
)
297 ((MessageFormat
*)fmt
)->setLocale(Locale(locale
));
300 U_CAPI
const char* U_EXPORT2
301 umsg_getLocale(const UMessageFormat
*fmt
)
307 return ((const MessageFormat
*)fmt
)->getLocale().getName();
310 U_CAPI
void U_EXPORT2
311 umsg_applyPattern(UMessageFormat
*fmt
,
312 const UChar
* pattern
,
313 int32_t patternLength
,
314 UParseError
* parseError
,
319 if(status
==NULL
||U_FAILURE(*status
)){
322 if(fmt
==NULL
||pattern
==NULL
||patternLength
<-1){
323 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
327 if(parseError
==NULL
){
330 if(patternLength
<-1){
331 patternLength
=u_strlen(pattern
);
334 ((MessageFormat
*)fmt
)->applyPattern(UnicodeString(pattern
,patternLength
),*parseError
,*status
);
337 U_CAPI
int32_t U_EXPORT2
338 umsg_toPattern(const UMessageFormat
*fmt
,
340 int32_t resultLength
,
344 if(status
==NULL
||U_FAILURE(*status
)){
347 if(fmt
==NULL
||resultLength
<0 || (resultLength
>0 && result
==0)){
348 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
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
);
359 ((const MessageFormat
*)fmt
)->toPattern(res
);
360 return res
.extract(result
, resultLength
, *status
);
364 umsg_format( const UMessageFormat
*fmt
,
366 int32_t resultLength
,
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
377 // start vararg processing
378 va_start(ap
, status
);
380 actLen
= umsg_vformat(fmt
,result
,resultLength
,ap
,status
);
382 // end vararg processing
388 U_CAPI
int32_t U_EXPORT2
389 umsg_vformat( const UMessageFormat
*fmt
,
391 int32_t resultLength
,
396 if(status
==0 || U_FAILURE(*status
))
400 if(fmt
==NULL
||resultLength
<0 || (resultLength
>0 && result
==0)) {
401 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
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];
412 // iterate through the vararg list, and get the arguments out
413 for(int32_t i
= 0; i
< count
; ++i
) {
420 switch(argTypes
[i
]) {
421 case Formattable::kDate
:
422 tempDate
= va_arg(ap
, UDate
);
423 args
[i
].setDate(tempDate
);
426 case Formattable::kDouble
:
427 tDouble
=va_arg(ap
, double);
428 args
[i
].setDouble(tDouble
);
431 case Formattable::kLong
:
432 tInt
= va_arg(ap
, int32_t);
433 args
[i
].setLong(tInt
);
436 case Formattable::kInt64
:
437 tInt64
= va_arg(ap
, int64_t);
438 args
[i
].setInt64(tInt64
);
441 case Formattable::kString
:
442 // For some reason, a temporary is needed
443 stringVal
= va_arg(ap
, UChar
*);
445 args
[i
].setString(UnicodeString(stringVal
));
447 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
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
459 case Formattable::kObject
:
460 // Unused argument number. Read and ignore a pointer argument.
465 // Unknown/unsupported argument type.
467 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
471 UnicodeString resultStr
;
472 FieldPosition
fieldPosition(0);
474 /* format the message */
475 ((const MessageFormat
*)fmt
)->format(args
,count
,resultStr
,fieldPosition
,*status
);
479 if(U_FAILURE(*status
)){
483 return resultStr
.extract(result
, resultLength
, *status
);
487 umsg_parse( const UMessageFormat
*fmt
,
489 int32_t sourceLength
,
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
499 // start vararg processing
500 va_start(ap
, status
);
502 umsg_vparse(fmt
,source
,sourceLength
,count
,ap
,status
);
504 // end vararg processing
508 U_CAPI
void U_EXPORT2
509 umsg_vparse(const UMessageFormat
*fmt
,
511 int32_t sourceLength
,
517 if(status
==NULL
||U_FAILURE(*status
))
521 if(fmt
==NULL
||source
==NULL
|| sourceLength
<-1 || count
==NULL
){
522 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
525 if(sourceLength
==-1){
526 sourceLength
=u_strlen(source
);
529 UnicodeString
srcString(source
,sourceLength
);
530 Formattable
*args
= ((const MessageFormat
*)fmt
)->parse(srcString
,*count
,*status
);
538 // assign formattables to varargs
539 for(int32_t i
= 0; i
< *count
; i
++) {
540 switch(args
[i
].getType()) {
542 case Formattable::kDate
:
543 aDate
= va_arg(ap
, UDate
*);
545 *aDate
= args
[i
].getDate();
547 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
551 case Formattable::kDouble
:
552 aDouble
= va_arg(ap
, double*);
554 *aDouble
= args
[i
].getDouble();
556 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
560 case Formattable::kLong
:
561 aInt
= va_arg(ap
, int32_t*);
563 *aInt
= (int32_t) args
[i
].getLong();
565 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
569 case Formattable::kInt64
:
570 aInt64
= va_arg(ap
, int64_t*);
572 *aInt64
= args
[i
].getInt64();
574 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
578 case Formattable::kString
:
579 aString
= va_arg(ap
, UChar
*);
581 args
[i
].getString(temp
);
583 temp
.extract(0,len
,aString
);
586 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
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]
598 // better not happen!
599 case Formattable::kArray
:
609 #define SINGLE_QUOTE ((UChar)0x0027)
610 #define CURLY_BRACE_LEFT ((UChar)0x007B)
611 #define CURLY_BRACE_RIGHT ((UChar)0x007D)
613 #define STATE_INITIAL 0
614 #define STATE_SINGLE_QUOTE 1
615 #define STATE_IN_QUOTE 2
616 #define STATE_MSG_ELEMENT 3
618 #define MAppend(c) if (len < destCapacity) dest[len++] = c; else len++
620 int32_t umsg_autoQuoteApostrophe(const UChar
* pattern
,
621 int32_t patternLength
,
623 int32_t destCapacity
,
626 int32_t state
= STATE_INITIAL
;
627 int32_t braceCount
= 0;
630 if (ec
== NULL
|| U_FAILURE(*ec
)) {
634 if (pattern
== NULL
|| patternLength
< -1 || (dest
== NULL
&& destCapacity
> 0)) {
635 *ec
= U_ILLEGAL_ARGUMENT_ERROR
;
638 U_ASSERT(destCapacity
>= 0);
640 if (patternLength
== -1) {
641 patternLength
= u_strlen(pattern
);
644 for (int i
= 0; i
< patternLength
; ++i
) {
645 UChar c
= pattern
[i
];
650 state
= STATE_SINGLE_QUOTE
;
652 case CURLY_BRACE_LEFT
:
653 state
= STATE_MSG_ELEMENT
;
659 case STATE_SINGLE_QUOTE
:
662 state
= STATE_INITIAL
;
664 case CURLY_BRACE_LEFT
:
665 case CURLY_BRACE_RIGHT
:
666 state
= STATE_IN_QUOTE
;
669 MAppend(SINGLE_QUOTE
);
670 state
= STATE_INITIAL
;
678 state
= STATE_INITIAL
;
683 case STATE_MSG_ELEMENT
:
685 case CURLY_BRACE_LEFT
:
688 case CURLY_BRACE_RIGHT
:
689 if (--braceCount
== 0) {
690 state
= STATE_INITIAL
;
696 default: // Never happens.
705 if (state
== STATE_SINGLE_QUOTE
|| state
== STATE_IN_QUOTE
) {
706 MAppend(SINGLE_QUOTE
);
709 return u_terminateUChars(dest
, destCapacity
, len
, ec
);
712 #endif /* #if !UCONFIG_NO_FORMATTING */