2 *******************************************************************************
4 * Copyright (C) 1999-2006, 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"
38 u_formatMessage(const char *locale
,
40 int32_t patternLength
,
48 //argument checking defered to subsequent method calls
49 // start vararg processing
52 actLen
= u_vformatMessage(locale
,pattern
,patternLength
,result
,resultLength
,ap
,status
);
53 // end vararg processing
59 U_CAPI
int32_t U_EXPORT2
60 u_vformatMessage( const char *locale
,
62 int32_t patternLength
,
69 //argument checking defered to subsequent method calls
70 UMessageFormat
*fmt
= umsg_open(pattern
,patternLength
,locale
,NULL
,status
);
71 int32_t retVal
= umsg_vformat(fmt
,result
,resultLength
,ap
,status
);
77 u_formatMessageWithError(const char *locale
,
79 int32_t patternLength
,
82 UParseError
*parseError
,
88 //argument checking defered to subsequent method calls
89 // start vararg processing
92 actLen
= u_vformatMessageWithError(locale
,pattern
,patternLength
,result
,resultLength
,parseError
,ap
,status
);
94 // end vararg processing
99 U_CAPI
int32_t U_EXPORT2
100 u_vformatMessageWithError( const char *locale
,
101 const UChar
*pattern
,
102 int32_t patternLength
,
104 int32_t resultLength
,
105 UParseError
*parseError
,
110 //argument checking defered to subsequent method calls
111 UMessageFormat
*fmt
= umsg_open(pattern
,patternLength
,locale
,parseError
,status
);
112 int32_t retVal
= umsg_vformat(fmt
,result
,resultLength
,ap
,status
);
118 // For parse, do the reverse of format:
119 // 1. Call through to the C++ APIs
120 // 2. Just assume the user passed in enough arguments.
121 // 3. Iterate through each formattable returned, and assign to the arguments
123 u_parseMessage( const char *locale
,
124 const UChar
*pattern
,
125 int32_t patternLength
,
127 int32_t sourceLength
,
132 //argument checking defered to subsequent method calls
134 // start vararg processing
135 va_start(ap
, status
);
137 u_vparseMessage(locale
,pattern
,patternLength
,source
,sourceLength
,ap
,status
);
138 // end vararg processing
142 U_CAPI
void U_EXPORT2
143 u_vparseMessage(const char *locale
,
144 const UChar
*pattern
,
145 int32_t patternLength
,
147 int32_t sourceLength
,
151 //argument checking defered to subsequent method calls
152 UMessageFormat
*fmt
= umsg_open(pattern
,patternLength
,locale
,NULL
,status
);
154 umsg_vparse(fmt
,source
,sourceLength
,&count
,ap
,status
);
159 u_parseMessageWithError(const char *locale
,
160 const UChar
*pattern
,
161 int32_t patternLength
,
163 int32_t sourceLength
,
170 //argument checking defered to subsequent method calls
172 // start vararg processing
173 va_start(ap
, status
);
175 u_vparseMessageWithError(locale
,pattern
,patternLength
,source
,sourceLength
,ap
,error
,status
);
176 // end vararg processing
179 U_CAPI
void U_EXPORT2
180 u_vparseMessageWithError(const char *locale
,
181 const UChar
*pattern
,
182 int32_t patternLength
,
184 int32_t sourceLength
,
189 //argument checking defered to subsequent method calls
190 UMessageFormat
*fmt
= umsg_open(pattern
,patternLength
,locale
,error
,status
);
192 umsg_vparse(fmt
,source
,sourceLength
,&count
,ap
,status
);
195 //////////////////////////////////////////////////////////////////////////////////
197 // Message format C API
199 /////////////////////////////////////////////////////////////////////////////////
202 U_CAPI UMessageFormat
* U_EXPORT2
203 umsg_open( const UChar
*pattern
,
204 int32_t patternLength
,
206 UParseError
*parseError
,
210 if(status
==NULL
|| U_FAILURE(*status
))
214 if(pattern
==NULL
||patternLength
<-1){
215 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
226 UMessageFormat
* retVal
= 0;
228 int32_t len
= (patternLength
== -1 ? u_strlen(pattern
) : patternLength
);
230 UnicodeString
patString((patternLength
== -1 ? TRUE
:FALSE
), pattern
,len
);
232 retVal
= (UMessageFormat
*) new MessageFormat(patString
,Locale(locale
),*parseError
,*status
);
235 *status
= U_MEMORY_ALLOCATION_ERROR
;
241 U_CAPI
void U_EXPORT2
242 umsg_close(UMessageFormat
* format
)
248 delete (MessageFormat
*) format
;
251 U_CAPI UMessageFormat U_EXPORT2
252 umsg_clone(const UMessageFormat
*fmt
,
256 if(status
==NULL
|| U_FAILURE(*status
)){
260 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
263 UMessageFormat retVal
= (UMessageFormat
)((MessageFormat
*)fmt
)->clone();
265 *status
= U_MEMORY_ALLOCATION_ERROR
;
271 U_CAPI
void U_EXPORT2
272 umsg_setLocale(UMessageFormat
*fmt
, const char* locale
)
278 ((MessageFormat
*)fmt
)->setLocale(Locale(locale
));
281 U_CAPI
const char* U_EXPORT2
282 umsg_getLocale(const UMessageFormat
*fmt
)
288 return ((const MessageFormat
*)fmt
)->getLocale().getName();
291 U_CAPI
void U_EXPORT2
292 umsg_applyPattern(UMessageFormat
*fmt
,
293 const UChar
* pattern
,
294 int32_t patternLength
,
295 UParseError
* parseError
,
300 if(status
==NULL
||U_FAILURE(*status
)){
303 if(fmt
==NULL
||pattern
==NULL
||patternLength
<-1){
304 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
308 if(parseError
==NULL
){
311 if(patternLength
<-1){
312 patternLength
=u_strlen(pattern
);
315 ((MessageFormat
*)fmt
)->applyPattern(UnicodeString(pattern
,patternLength
),*parseError
,*status
);
318 U_CAPI
int32_t U_EXPORT2
319 umsg_toPattern(const UMessageFormat
*fmt
,
321 int32_t resultLength
,
325 if(status
==NULL
||U_FAILURE(*status
)){
328 if(fmt
==NULL
||resultLength
<0 || (resultLength
>0 && result
==0)){
329 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
335 if(!(result
==NULL
&& resultLength
==0)) {
336 // NULL destination for pure preflighting: empty dummy string
337 // otherwise, alias the destination buffer
338 res
.setTo(result
, 0, resultLength
);
340 ((const MessageFormat
*)fmt
)->toPattern(res
);
341 return res
.extract(result
, resultLength
, *status
);
345 umsg_format( const UMessageFormat
*fmt
,
347 int32_t resultLength
,
353 //argument checking defered to last method call umsg_vformat which
354 //saves time when arguments are valid and we dont care when arguments are not
355 //since we return an error anyway
358 // start vararg processing
359 va_start(ap
, status
);
361 actLen
= umsg_vformat(fmt
,result
,resultLength
,ap
,status
);
363 // end vararg processing
371 * This class isolates our access to private internal methods of
372 * MessageFormat. It is never instantiated; it exists only for C++
375 class MessageFormatAdapter
{
377 static const Formattable::Type
* getArgTypeList(const MessageFormat
& m
,
380 const Formattable::Type
*
381 MessageFormatAdapter::getArgTypeList(const MessageFormat
& m
,
383 return m
.getArgTypeList(count
);
387 U_CAPI
int32_t U_EXPORT2
388 umsg_vformat( const UMessageFormat
*fmt
,
390 int32_t resultLength
,
395 if(status
==0 || U_FAILURE(*status
))
399 if(fmt
==NULL
||resultLength
<0 || (resultLength
>0 && result
==0)) {
400 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
405 const Formattable::Type
* argTypes
=
406 MessageFormatAdapter::getArgTypeList(*(const MessageFormat
*)fmt
, count
);
407 // Allocate at least one element. Allocating an array of length
408 // zero causes problems on some platforms (e.g. Win32).
409 Formattable
* args
= new Formattable
[count
? count
: 1];
411 // iterate through the vararg list, and get the arguments out
412 for(int32_t i
= 0; i
< count
; ++i
) {
419 switch(argTypes
[i
]) {
420 case Formattable::kDate
:
421 tempDate
= va_arg(ap
, UDate
);
422 args
[i
].setDate(tempDate
);
425 case Formattable::kDouble
:
426 tDouble
=va_arg(ap
, double);
427 args
[i
].setDouble(tDouble
);
430 case Formattable::kLong
:
431 tInt
= va_arg(ap
, int32_t);
432 args
[i
].setLong(tInt
);
435 case Formattable::kInt64
:
436 tInt64
= va_arg(ap
, int64_t);
437 args
[i
].setInt64(tInt64
);
440 case Formattable::kString
:
441 // For some reason, a temporary is needed
442 stringVal
= va_arg(ap
, UChar
*);
444 args
[i
].setString(stringVal
);
446 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
450 case Formattable::kArray
:
451 // throw away this argument
452 // this is highly platform-dependent, and probably won't work
453 // so, if you try to skip arguments in the list (and not use them)
454 // you'll probably crash
458 case Formattable::kObject
:
459 // This will never happen because MessageFormat doesn't
460 // support kObject. When MessageFormat is changed to
461 // understand MeasureFormats, modify this code to do the
462 // right thing. [alan]
467 UnicodeString resultStr
;
468 FieldPosition
fieldPosition(0);
470 /* format the message */
471 ((const MessageFormat
*)fmt
)->format(args
,count
,resultStr
,fieldPosition
,*status
);
475 if(U_FAILURE(*status
)){
479 return resultStr
.extract(result
, resultLength
, *status
);
483 umsg_parse( const UMessageFormat
*fmt
,
485 int32_t sourceLength
,
491 //argument checking defered to last method call umsg_vparse which
492 //saves time when arguments are valid and we dont care when arguments are not
493 //since we return an error anyway
495 // start vararg processing
496 va_start(ap
, status
);
498 umsg_vparse(fmt
,source
,sourceLength
,count
,ap
,status
);
500 // end vararg processing
504 U_CAPI
void U_EXPORT2
505 umsg_vparse(const UMessageFormat
*fmt
,
507 int32_t sourceLength
,
513 if(status
==NULL
||U_FAILURE(*status
))
517 if(fmt
==NULL
||source
==NULL
|| sourceLength
<-1 || count
==NULL
){
518 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
521 if(sourceLength
==-1){
522 sourceLength
=u_strlen(source
);
525 UnicodeString
srcString(source
,sourceLength
);
526 Formattable
*args
= ((const MessageFormat
*)fmt
)->parse(source
,*count
,*status
);
534 // assign formattables to varargs
535 for(int32_t i
= 0; i
< *count
; i
++) {
536 switch(args
[i
].getType()) {
538 case Formattable::kDate
:
539 aDate
= va_arg(ap
, UDate
*);
541 *aDate
= args
[i
].getDate();
543 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
547 case Formattable::kDouble
:
548 aDouble
= va_arg(ap
, double*);
550 *aDouble
= args
[i
].getDouble();
552 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
556 case Formattable::kLong
:
557 aInt
= va_arg(ap
, int32_t*);
559 *aInt
= (int32_t) args
[i
].getLong();
561 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
565 case Formattable::kInt64
:
566 aInt64
= va_arg(ap
, int64_t*);
568 *aInt64
= args
[i
].getInt64();
570 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
574 case Formattable::kString
:
575 aString
= va_arg(ap
, UChar
*);
577 args
[i
].getString(temp
);
579 temp
.extract(0,len
,aString
);
582 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
586 case Formattable::kObject
:
587 // This will never happen because MessageFormat doesn't
588 // support kObject. When MessageFormat is changed to
589 // understand MeasureFormats, modify this code to do the
590 // right thing. [alan]
594 // better not happen!
595 case Formattable::kArray
:
605 #define SINGLE_QUOTE ((UChar)0x0027)
606 #define CURLY_BRACE_LEFT ((UChar)0x007B)
607 #define CURLY_BRACE_RIGHT ((UChar)0x007D)
609 #define STATE_INITIAL 0
610 #define STATE_SINGLE_QUOTE 1
611 #define STATE_IN_QUOTE 2
612 #define STATE_MSG_ELEMENT 3
614 #define MAppend(c) if (len < destCapacity) dest[len++] = c; else len++
616 int32_t umsg_autoQuoteApostrophe(const UChar
* pattern
,
617 int32_t patternLength
,
619 int32_t destCapacity
,
622 int32_t state
= STATE_INITIAL
;
623 int32_t braceCount
= 0;
626 if (ec
== NULL
|| U_FAILURE(*ec
)) {
630 if (pattern
== NULL
|| patternLength
< -1 || (dest
== NULL
&& destCapacity
> 0)) {
631 *ec
= U_ILLEGAL_ARGUMENT_ERROR
;
635 if (patternLength
== -1) {
636 patternLength
= u_strlen(pattern
);
639 for (int i
= 0; i
< patternLength
; ++i
) {
640 UChar c
= pattern
[i
];
645 state
= STATE_SINGLE_QUOTE
;
647 case CURLY_BRACE_LEFT
:
648 state
= STATE_MSG_ELEMENT
;
654 case STATE_SINGLE_QUOTE
:
657 state
= STATE_INITIAL
;
659 case CURLY_BRACE_LEFT
:
660 case CURLY_BRACE_RIGHT
:
661 state
= STATE_IN_QUOTE
;
664 MAppend(SINGLE_QUOTE
);
665 state
= STATE_INITIAL
;
673 state
= STATE_INITIAL
;
678 case STATE_MSG_ELEMENT
:
680 case CURLY_BRACE_LEFT
:
683 case CURLY_BRACE_RIGHT
:
684 if (--braceCount
== 0) {
685 state
= STATE_INITIAL
;
691 default: // Never happens.
699 if (state
== STATE_SINGLE_QUOTE
|| state
== STATE_IN_QUOTE
) {
700 MAppend(SINGLE_QUOTE
);
703 return u_terminateUChars(dest
, destCapacity
, len
, ec
);
706 #endif /* #if !UCONFIG_NO_FORMATTING */