1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
6 * Copyright (C) 1999-2012, International Business Machines
7 * Corporation and others. All Rights Reserved.
9 *******************************************************************************
12 * tab size: 8 (not used)
15 * This is a C wrapper to MessageFormat C++ API.
19 * 08/5/2001 Ram Added C wrappers for C++ API. Changed implementation of old API's
20 * Removed pattern parser.
24 #include "unicode/utypes.h"
26 #if !UCONFIG_NO_FORMATTING
28 #include "unicode/umsg.h"
29 #include "unicode/ustring.h"
30 #include "unicode/fmtable.h"
31 #include "unicode/msgfmt.h"
32 #include "unicode/unistr.h"
39 * This class isolates our access to private internal methods of
40 * MessageFormat. It is never instantiated; it exists only for C++
43 class MessageFormatAdapter
{
45 static const Formattable::Type
* getArgTypeList(const MessageFormat
& m
,
47 static UBool
hasArgTypeConflicts(const MessageFormat
& m
) {
48 return m
.hasArgTypeConflicts
;
51 const Formattable::Type
*
52 MessageFormatAdapter::getArgTypeList(const MessageFormat
& m
,
54 return m
.getArgTypeList(count
);
61 u_formatMessage(const char *locale
,
63 int32_t patternLength
,
71 //argument checking defered to subsequent method calls
72 // start vararg processing
75 actLen
= u_vformatMessage(locale
,pattern
,patternLength
,result
,resultLength
,ap
,status
);
76 // end vararg processing
82 U_CAPI
int32_t U_EXPORT2
83 u_vformatMessage( const char *locale
,
85 int32_t patternLength
,
92 //argument checking defered to subsequent method calls
93 UMessageFormat
*fmt
= umsg_open(pattern
,patternLength
,locale
,NULL
,status
);
94 int32_t retVal
= umsg_vformat(fmt
,result
,resultLength
,ap
,status
);
100 u_formatMessageWithError(const char *locale
,
101 const UChar
*pattern
,
102 int32_t patternLength
,
104 int32_t resultLength
,
105 UParseError
*parseError
,
111 //argument checking defered to subsequent method calls
112 // start vararg processing
113 va_start(ap
, status
);
115 actLen
= u_vformatMessageWithError(locale
,pattern
,patternLength
,result
,resultLength
,parseError
,ap
,status
);
117 // end vararg processing
122 U_CAPI
int32_t U_EXPORT2
123 u_vformatMessageWithError( const char *locale
,
124 const UChar
*pattern
,
125 int32_t patternLength
,
127 int32_t resultLength
,
128 UParseError
*parseError
,
133 //argument checking defered to subsequent method calls
134 UMessageFormat
*fmt
= umsg_open(pattern
,patternLength
,locale
,parseError
,status
);
135 int32_t retVal
= umsg_vformat(fmt
,result
,resultLength
,ap
,status
);
141 // For parse, do the reverse of format:
142 // 1. Call through to the C++ APIs
143 // 2. Just assume the user passed in enough arguments.
144 // 3. Iterate through each formattable returned, and assign to the arguments
146 u_parseMessage( const char *locale
,
147 const UChar
*pattern
,
148 int32_t patternLength
,
150 int32_t sourceLength
,
155 //argument checking defered to subsequent method calls
157 // start vararg processing
158 va_start(ap
, status
);
160 u_vparseMessage(locale
,pattern
,patternLength
,source
,sourceLength
,ap
,status
);
161 // end vararg processing
165 U_CAPI
void U_EXPORT2
166 u_vparseMessage(const char *locale
,
167 const UChar
*pattern
,
168 int32_t patternLength
,
170 int32_t sourceLength
,
174 //argument checking defered to subsequent method calls
175 UMessageFormat
*fmt
= umsg_open(pattern
,patternLength
,locale
,NULL
,status
);
177 umsg_vparse(fmt
,source
,sourceLength
,&count
,ap
,status
);
182 u_parseMessageWithError(const char *locale
,
183 const UChar
*pattern
,
184 int32_t patternLength
,
186 int32_t sourceLength
,
193 //argument checking defered to subsequent method calls
195 // start vararg processing
196 va_start(ap
, status
);
198 u_vparseMessageWithError(locale
,pattern
,patternLength
,source
,sourceLength
,ap
,error
,status
);
199 // end vararg processing
202 U_CAPI
void U_EXPORT2
203 u_vparseMessageWithError(const char *locale
,
204 const UChar
*pattern
,
205 int32_t patternLength
,
207 int32_t sourceLength
,
212 //argument checking defered to subsequent method calls
213 UMessageFormat
*fmt
= umsg_open(pattern
,patternLength
,locale
,error
,status
);
215 umsg_vparse(fmt
,source
,sourceLength
,&count
,ap
,status
);
218 //////////////////////////////////////////////////////////////////////////////////
220 // Message format C API
222 /////////////////////////////////////////////////////////////////////////////////
225 U_CAPI UMessageFormat
* U_EXPORT2
226 umsg_open( const UChar
*pattern
,
227 int32_t patternLength
,
229 UParseError
*parseError
,
233 if(status
==NULL
|| U_FAILURE(*status
))
237 if(pattern
==NULL
||patternLength
<-1){
238 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
248 int32_t len
= (patternLength
== -1 ? u_strlen(pattern
) : patternLength
);
249 UnicodeString
patString(patternLength
== -1, pattern
, len
);
251 MessageFormat
* retVal
= new MessageFormat(patString
,Locale(locale
),*parseError
,*status
);
253 *status
= U_MEMORY_ALLOCATION_ERROR
;
256 if (U_SUCCESS(*status
) && MessageFormatAdapter::hasArgTypeConflicts(*retVal
)) {
257 *status
= U_ARGUMENT_TYPE_MISMATCH
;
259 return (UMessageFormat
*)retVal
;
262 U_CAPI
void U_EXPORT2
263 umsg_close(UMessageFormat
* format
)
269 delete (MessageFormat
*) format
;
272 U_CAPI UMessageFormat U_EXPORT2
273 umsg_clone(const UMessageFormat
*fmt
,
277 if(status
==NULL
|| U_FAILURE(*status
)){
281 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
284 UMessageFormat retVal
= (UMessageFormat
)((MessageFormat
*)fmt
)->clone();
286 *status
= U_MEMORY_ALLOCATION_ERROR
;
292 U_CAPI
void U_EXPORT2
293 umsg_setLocale(UMessageFormat
*fmt
, const char* locale
)
299 ((MessageFormat
*)fmt
)->setLocale(Locale(locale
));
302 U_CAPI
const char* U_EXPORT2
303 umsg_getLocale(const UMessageFormat
*fmt
)
309 return ((const MessageFormat
*)fmt
)->getLocale().getName();
312 U_CAPI
void U_EXPORT2
313 umsg_applyPattern(UMessageFormat
*fmt
,
314 const UChar
* pattern
,
315 int32_t patternLength
,
316 UParseError
* parseError
,
321 if(status
==NULL
||U_FAILURE(*status
)){
324 if(fmt
==NULL
||pattern
==NULL
||patternLength
<-1){
325 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
329 if(parseError
==NULL
){
332 if(patternLength
<-1){
333 patternLength
=u_strlen(pattern
);
336 ((MessageFormat
*)fmt
)->applyPattern(UnicodeString(pattern
,patternLength
),*parseError
,*status
);
339 U_CAPI
int32_t U_EXPORT2
340 umsg_toPattern(const UMessageFormat
*fmt
,
342 int32_t resultLength
,
346 if(status
==NULL
||U_FAILURE(*status
)){
349 if(fmt
==NULL
||resultLength
<0 || (resultLength
>0 && result
==0)){
350 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
356 if(!(result
==NULL
&& resultLength
==0)) {
357 // NULL destination for pure preflighting: empty dummy string
358 // otherwise, alias the destination buffer
359 res
.setTo(result
, 0, resultLength
);
361 ((const MessageFormat
*)fmt
)->toPattern(res
);
362 return res
.extract(result
, resultLength
, *status
);
366 umsg_format( const UMessageFormat
*fmt
,
368 int32_t resultLength
,
374 //argument checking defered to last method call umsg_vformat which
375 //saves time when arguments are valid and we dont care when arguments are not
376 //since we return an error anyway
379 // start vararg processing
380 va_start(ap
, status
);
382 actLen
= umsg_vformat(fmt
,result
,resultLength
,ap
,status
);
384 // end vararg processing
390 U_CAPI
int32_t U_EXPORT2
391 umsg_vformat( const UMessageFormat
*fmt
,
393 int32_t resultLength
,
398 if(status
==0 || U_FAILURE(*status
))
402 if(fmt
==NULL
||resultLength
<0 || (resultLength
>0 && result
==0)) {
403 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
408 const Formattable::Type
* argTypes
=
409 MessageFormatAdapter::getArgTypeList(*(const MessageFormat
*)fmt
, count
);
410 // Allocate at least one element. Allocating an array of length
411 // zero causes problems on some platforms (e.g. Win32).
412 Formattable
* args
= new Formattable
[count
? count
: 1];
414 // iterate through the vararg list, and get the arguments out
415 for(int32_t i
= 0; i
< count
; ++i
) {
422 switch(argTypes
[i
]) {
423 case Formattable::kDate
:
424 tempDate
= va_arg(ap
, UDate
);
425 args
[i
].setDate(tempDate
);
428 case Formattable::kDouble
:
429 tDouble
=va_arg(ap
, double);
430 args
[i
].setDouble(tDouble
);
433 case Formattable::kLong
:
434 tInt
= va_arg(ap
, int32_t);
435 args
[i
].setLong(tInt
);
438 case Formattable::kInt64
:
439 tInt64
= va_arg(ap
, int64_t);
440 args
[i
].setInt64(tInt64
);
443 case Formattable::kString
:
444 // For some reason, a temporary is needed
445 stringVal
= va_arg(ap
, UChar
*);
447 args
[i
].setString(UnicodeString(stringVal
));
449 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
453 case Formattable::kArray
:
454 // throw away this argument
455 // this is highly platform-dependent, and probably won't work
456 // so, if you try to skip arguments in the list (and not use them)
457 // you'll probably crash
461 case Formattable::kObject
:
462 // Unused argument number. Read and ignore a pointer argument.
467 // Unknown/unsupported argument type.
469 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
473 UnicodeString resultStr
;
474 FieldPosition
fieldPosition(FieldPosition::DONT_CARE
);
476 /* format the message */
477 ((const MessageFormat
*)fmt
)->format(args
,count
,resultStr
,fieldPosition
,*status
);
481 if(U_FAILURE(*status
)){
485 return resultStr
.extract(result
, resultLength
, *status
);
489 umsg_parse( const UMessageFormat
*fmt
,
491 int32_t sourceLength
,
497 //argument checking defered to last method call umsg_vparse which
498 //saves time when arguments are valid and we dont care when arguments are not
499 //since we return an error anyway
501 // start vararg processing
502 va_start(ap
, status
);
504 umsg_vparse(fmt
,source
,sourceLength
,count
,ap
,status
);
506 // end vararg processing
510 U_CAPI
void U_EXPORT2
511 umsg_vparse(const UMessageFormat
*fmt
,
513 int32_t sourceLength
,
519 if(status
==NULL
||U_FAILURE(*status
))
523 if(fmt
==NULL
||source
==NULL
|| sourceLength
<-1 || count
==NULL
){
524 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
527 if(sourceLength
==-1){
528 sourceLength
=u_strlen(source
);
531 UnicodeString
srcString(source
,sourceLength
);
532 Formattable
*args
= ((const MessageFormat
*)fmt
)->parse(srcString
,*count
,*status
);
540 // assign formattables to varargs
541 for(int32_t i
= 0; i
< *count
; i
++) {
542 switch(args
[i
].getType()) {
544 case Formattable::kDate
:
545 aDate
= va_arg(ap
, UDate
*);
547 *aDate
= args
[i
].getDate();
549 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
553 case Formattable::kDouble
:
554 aDouble
= va_arg(ap
, double*);
556 *aDouble
= args
[i
].getDouble();
558 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
562 case Formattable::kLong
:
563 aInt
= va_arg(ap
, int32_t*);
565 *aInt
= (int32_t) args
[i
].getLong();
567 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
571 case Formattable::kInt64
:
572 aInt64
= va_arg(ap
, int64_t*);
574 *aInt64
= args
[i
].getInt64();
576 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
580 case Formattable::kString
:
581 aString
= va_arg(ap
, UChar
*);
583 args
[i
].getString(temp
);
585 temp
.extract(0,len
,aString
);
588 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
592 case Formattable::kObject
:
593 // This will never happen because MessageFormat doesn't
594 // support kObject. When MessageFormat is changed to
595 // understand MeasureFormats, modify this code to do the
596 // right thing. [alan]
600 // better not happen!
601 case Formattable::kArray
:
611 #define SINGLE_QUOTE ((UChar)0x0027)
612 #define CURLY_BRACE_LEFT ((UChar)0x007B)
613 #define CURLY_BRACE_RIGHT ((UChar)0x007D)
615 #define STATE_INITIAL 0
616 #define STATE_SINGLE_QUOTE 1
617 #define STATE_IN_QUOTE 2
618 #define STATE_MSG_ELEMENT 3
620 #define MAppend(c) if (len < destCapacity) dest[len++] = c; else len++
622 int32_t umsg_autoQuoteApostrophe(const UChar
* pattern
,
623 int32_t patternLength
,
625 int32_t destCapacity
,
628 int32_t state
= STATE_INITIAL
;
629 int32_t braceCount
= 0;
632 if (ec
== NULL
|| U_FAILURE(*ec
)) {
636 if (pattern
== NULL
|| patternLength
< -1 || (dest
== NULL
&& destCapacity
> 0)) {
637 *ec
= U_ILLEGAL_ARGUMENT_ERROR
;
640 U_ASSERT(destCapacity
>= 0);
642 if (patternLength
== -1) {
643 patternLength
= u_strlen(pattern
);
646 for (int i
= 0; i
< patternLength
; ++i
) {
647 UChar c
= pattern
[i
];
652 state
= STATE_SINGLE_QUOTE
;
654 case CURLY_BRACE_LEFT
:
655 state
= STATE_MSG_ELEMENT
;
661 case STATE_SINGLE_QUOTE
:
664 state
= STATE_INITIAL
;
666 case CURLY_BRACE_LEFT
:
667 case CURLY_BRACE_RIGHT
:
668 state
= STATE_IN_QUOTE
;
671 MAppend(SINGLE_QUOTE
);
672 state
= STATE_INITIAL
;
680 state
= STATE_INITIAL
;
685 case STATE_MSG_ELEMENT
:
687 case CURLY_BRACE_LEFT
:
690 case CURLY_BRACE_RIGHT
:
691 if (--braceCount
== 0) {
692 state
= STATE_INITIAL
;
698 default: // Never happens.
707 if (state
== STATE_SINGLE_QUOTE
|| state
== STATE_IN_QUOTE
) {
708 MAppend(SINGLE_QUOTE
);
711 return u_terminateUChars(dest
, destCapacity
, len
, ec
);
714 #endif /* #if !UCONFIG_NO_FORMATTING */