1 // Copyright (C) 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 */