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 */