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
!=0) || patternLength
<-1) {
325 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
329 if(parseError
==NULL
){
333 // UnicodeString(pattern, -1) calls u_strlen().
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(FieldPosition::DONT_CARE
);
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 */