Home | History | Annotate | Download | only in i18n
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 *******************************************************************************
      5 *
      6 *   Copyright (C) 1999-2012, International Business Machines
      7 *   Corporation and others.  All Rights Reserved.
      8 *
      9 *******************************************************************************
     10 *   file name:  umsg.cpp
     11 *   encoding:   UTF-8
     12 *   tab size:   8 (not used)
     13 *   indentation:4
     14 *
     15 * This is a C wrapper to MessageFormat C++ API.
     16 *
     17 *   Change history:
     18 *
     19 *   08/5/2001  Ram         Added C wrappers for C++ API. Changed implementation of old API's
     20 *                          Removed pattern parser.
     21 *
     22 */
     23 
     24 #include "unicode/utypes.h"
     25 
     26 #if !UCONFIG_NO_FORMATTING
     27 
     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"
     33 #include "cpputils.h"
     34 #include "uassert.h"
     35 #include "ustr_imp.h"
     36 
     37 U_NAMESPACE_BEGIN
     38 /**
     39  * This class isolates our access to private internal methods of
     40  * MessageFormat.  It is never instantiated; it exists only for C++
     41  * access management.
     42  */
     43 class MessageFormatAdapter {
     44 public:
     45     static const Formattable::Type* getArgTypeList(const MessageFormat& m,
     46                                                    int32_t& count);
     47     static UBool hasArgTypeConflicts(const MessageFormat& m) {
     48         return m.hasArgTypeConflicts;
     49     }
     50 };
     51 const Formattable::Type*
     52 MessageFormatAdapter::getArgTypeList(const MessageFormat& m,
     53                                      int32_t& count) {
     54     return m.getArgTypeList(count);
     55 }
     56 U_NAMESPACE_END
     57 
     58 U_NAMESPACE_USE
     59 
     60 U_CAPI int32_t
     61 u_formatMessage(const char  *locale,
     62                 const UChar *pattern,
     63                 int32_t     patternLength,
     64                 UChar       *result,
     65                 int32_t     resultLength,
     66                 UErrorCode  *status,
     67                 ...)
     68 {
     69     va_list    ap;
     70     int32_t actLen;
     71     //argument checking defered to subsequent method calls
     72     // start vararg processing
     73     va_start(ap, status);
     74 
     75     actLen = u_vformatMessage(locale,pattern,patternLength,result,resultLength,ap,status);
     76     // end vararg processing
     77     va_end(ap);
     78 
     79     return actLen;
     80 }
     81 
     82 U_CAPI int32_t U_EXPORT2
     83 u_vformatMessage(   const char  *locale,
     84                     const UChar *pattern,
     85                     int32_t     patternLength,
     86                     UChar       *result,
     87                     int32_t     resultLength,
     88                     va_list     ap,
     89                     UErrorCode  *status)
     90 
     91 {
     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);
     95     umsg_close(fmt);
     96     return retVal;
     97 }
     98 
     99 U_CAPI int32_t
    100 u_formatMessageWithError(const char *locale,
    101                         const UChar *pattern,
    102                         int32_t     patternLength,
    103                         UChar       *result,
    104                         int32_t     resultLength,
    105                         UParseError *parseError,
    106                         UErrorCode  *status,
    107                         ...)
    108 {
    109     va_list    ap;
    110     int32_t actLen;
    111     //argument checking defered to subsequent method calls
    112     // start vararg processing
    113     va_start(ap, status);
    114 
    115     actLen = u_vformatMessageWithError(locale,pattern,patternLength,result,resultLength,parseError,ap,status);
    116 
    117     // end vararg processing
    118     va_end(ap);
    119     return actLen;
    120 }
    121 
    122 U_CAPI int32_t U_EXPORT2
    123 u_vformatMessageWithError(  const char  *locale,
    124                             const UChar *pattern,
    125                             int32_t     patternLength,
    126                             UChar       *result,
    127                             int32_t     resultLength,
    128                             UParseError *parseError,
    129                             va_list     ap,
    130                             UErrorCode  *status)
    131 
    132 {
    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);
    136     umsg_close(fmt);
    137     return retVal;
    138 }
    139 
    140 
    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
    145 U_CAPI void
    146 u_parseMessage( const char   *locale,
    147                 const UChar  *pattern,
    148                 int32_t      patternLength,
    149                 const UChar  *source,
    150                 int32_t      sourceLength,
    151                 UErrorCode   *status,
    152                 ...)
    153 {
    154     va_list    ap;
    155     //argument checking defered to subsequent method calls
    156 
    157     // start vararg processing
    158     va_start(ap, status);
    159 
    160     u_vparseMessage(locale,pattern,patternLength,source,sourceLength,ap,status);
    161     // end vararg processing
    162     va_end(ap);
    163 }
    164 
    165 U_CAPI void U_EXPORT2
    166 u_vparseMessage(const char  *locale,
    167                 const UChar *pattern,
    168                 int32_t     patternLength,
    169                 const UChar *source,
    170                 int32_t     sourceLength,
    171                 va_list     ap,
    172                 UErrorCode  *status)
    173 {
    174     //argument checking defered to subsequent method calls
    175     UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,NULL,status);
    176     int32_t count = 0;
    177     umsg_vparse(fmt,source,sourceLength,&count,ap,status);
    178     umsg_close(fmt);
    179 }
    180 
    181 U_CAPI void
    182 u_parseMessageWithError(const char  *locale,
    183                         const UChar *pattern,
    184                         int32_t     patternLength,
    185                         const UChar *source,
    186                         int32_t     sourceLength,
    187                         UParseError *error,
    188                         UErrorCode  *status,
    189                         ...)
    190 {
    191     va_list    ap;
    192 
    193     //argument checking defered to subsequent method calls
    194 
    195     // start vararg processing
    196     va_start(ap, status);
    197 
    198     u_vparseMessageWithError(locale,pattern,patternLength,source,sourceLength,ap,error,status);
    199     // end vararg processing
    200     va_end(ap);
    201 }
    202 U_CAPI void U_EXPORT2
    203 u_vparseMessageWithError(const char  *locale,
    204                          const UChar *pattern,
    205                          int32_t     patternLength,
    206                          const UChar *source,
    207                          int32_t     sourceLength,
    208                          va_list     ap,
    209                          UParseError *error,
    210                          UErrorCode* status)
    211 {
    212     //argument checking defered to subsequent method calls
    213     UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,error,status);
    214     int32_t count = 0;
    215     umsg_vparse(fmt,source,sourceLength,&count,ap,status);
    216     umsg_close(fmt);
    217 }
    218 //////////////////////////////////////////////////////////////////////////////////
    219 //
    220 //  Message format C API
    221 //
    222 /////////////////////////////////////////////////////////////////////////////////
    223 
    224 
    225 U_CAPI UMessageFormat* U_EXPORT2
    226 umsg_open(  const UChar     *pattern,
    227             int32_t         patternLength,
    228             const  char     *locale,
    229             UParseError     *parseError,
    230             UErrorCode      *status)
    231 {
    232     //check arguments
    233     if(status==NULL || U_FAILURE(*status))
    234     {
    235       return 0;
    236     }
    237     if(pattern==NULL||patternLength<-1){
    238         *status=U_ILLEGAL_ARGUMENT_ERROR;
    239         return 0;
    240     }
    241 
    242     UParseError tErr;
    243     if(parseError==NULL)
    244     {
    245         parseError = &tErr;
    246     }
    247 
    248     int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength);
    249     UnicodeString patString(patternLength == -1, pattern, len);
    250 
    251     MessageFormat* retVal = new MessageFormat(patString,Locale(locale),*parseError,*status);
    252     if(retVal == NULL) {
    253         *status = U_MEMORY_ALLOCATION_ERROR;
    254         return NULL;
    255     }
    256     if (U_SUCCESS(*status) && MessageFormatAdapter::hasArgTypeConflicts(*retVal)) {
    257         *status = U_ARGUMENT_TYPE_MISMATCH;
    258     }
    259     return (UMessageFormat*)retVal;
    260 }
    261 
    262 U_CAPI void U_EXPORT2
    263 umsg_close(UMessageFormat* format)
    264 {
    265     //check arguments
    266     if(format==NULL){
    267         return;
    268     }
    269     delete (MessageFormat*) format;
    270 }
    271 
    272 U_CAPI UMessageFormat U_EXPORT2
    273 umsg_clone(const UMessageFormat *fmt,
    274            UErrorCode *status)
    275 {
    276     //check arguments
    277     if(status==NULL || U_FAILURE(*status)){
    278         return NULL;
    279     }
    280     if(fmt==NULL){
    281         *status = U_ILLEGAL_ARGUMENT_ERROR;
    282         return NULL;
    283     }
    284     UMessageFormat retVal = (UMessageFormat)((MessageFormat*)fmt)->clone();
    285     if(retVal == 0) {
    286         *status = U_MEMORY_ALLOCATION_ERROR;
    287         return 0;
    288     }
    289     return retVal;
    290 }
    291 
    292 U_CAPI void  U_EXPORT2
    293 umsg_setLocale(UMessageFormat *fmt, const char* locale)
    294 {
    295     //check arguments
    296     if(fmt==NULL){
    297         return;
    298     }
    299     ((MessageFormat*)fmt)->setLocale(Locale(locale));
    300 }
    301 
    302 U_CAPI const char*  U_EXPORT2
    303 umsg_getLocale(const UMessageFormat *fmt)
    304 {
    305     //check arguments
    306     if(fmt==NULL){
    307         return "";
    308     }
    309     return ((const MessageFormat*)fmt)->getLocale().getName();
    310 }
    311 
    312 U_CAPI void  U_EXPORT2
    313 umsg_applyPattern(UMessageFormat *fmt,
    314                            const UChar* pattern,
    315                            int32_t patternLength,
    316                            UParseError* parseError,
    317                            UErrorCode* status)
    318 {
    319     //check arguments
    320     UParseError tErr;
    321     if(status ==NULL||U_FAILURE(*status)){
    322         return ;
    323     }
    324     if(fmt==NULL || (pattern==NULL && patternLength!=0) || patternLength<-1) {
    325         *status=U_ILLEGAL_ARGUMENT_ERROR;
    326         return ;
    327     }
    328 
    329     if(parseError==NULL){
    330       parseError = &tErr;
    331     }
    332 
    333     // UnicodeString(pattern, -1) calls u_strlen().
    334     ((MessageFormat*)fmt)->applyPattern(UnicodeString(pattern,patternLength),*parseError,*status);
    335 }
    336 
    337 U_CAPI int32_t  U_EXPORT2
    338 umsg_toPattern(const UMessageFormat *fmt,
    339                UChar* result,
    340                int32_t resultLength,
    341                UErrorCode* status)
    342 {
    343     //check arguments
    344     if(status ==NULL||U_FAILURE(*status)){
    345         return -1;
    346     }
    347     if(fmt==NULL||resultLength<0 || (resultLength>0 && result==0)){
    348         *status=U_ILLEGAL_ARGUMENT_ERROR;
    349         return -1;
    350     }
    351 
    352 
    353     UnicodeString res;
    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);
    358     }
    359     ((const MessageFormat*)fmt)->toPattern(res);
    360     return res.extract(result, resultLength, *status);
    361 }
    362 
    363 U_CAPI int32_t
    364 umsg_format(    const UMessageFormat *fmt,
    365                 UChar          *result,
    366                 int32_t        resultLength,
    367                 UErrorCode     *status,
    368                 ...)
    369 {
    370     va_list    ap;
    371     int32_t actLen;
    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
    375 
    376 
    377     // start vararg processing
    378     va_start(ap, status);
    379 
    380     actLen = umsg_vformat(fmt,result,resultLength,ap,status);
    381 
    382     // end vararg processing
    383     va_end(ap);
    384 
    385     return actLen;
    386 }
    387 
    388 U_CAPI int32_t U_EXPORT2
    389 umsg_vformat(   const UMessageFormat *fmt,
    390                 UChar          *result,
    391                 int32_t        resultLength,
    392                 va_list        ap,
    393                 UErrorCode     *status)
    394 {
    395     //check arguments
    396     if(status==0 || U_FAILURE(*status))
    397     {
    398         return -1;
    399     }
    400     if(fmt==NULL||resultLength<0 || (resultLength>0 && result==0)) {
    401         *status=U_ILLEGAL_ARGUMENT_ERROR;
    402         return -1;
    403     }
    404 
    405     int32_t count =0;
    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];
    411 
    412     // iterate through the vararg list, and get the arguments out
    413     for(int32_t i = 0; i < count; ++i) {
    414 
    415         UChar *stringVal;
    416         double tDouble=0;
    417         int32_t tInt =0;
    418         int64_t tInt64 = 0;
    419         UDate tempDate = 0;
    420         switch(argTypes[i]) {
    421         case Formattable::kDate:
    422             tempDate = va_arg(ap, UDate);
    423             args[i].setDate(tempDate);
    424             break;
    425 
    426         case Formattable::kDouble:
    427             tDouble =va_arg(ap, double);
    428             args[i].setDouble(tDouble);
    429             break;
    430 
    431         case Formattable::kLong:
    432             tInt = va_arg(ap, int32_t);
    433             args[i].setLong(tInt);
    434             break;
    435 
    436         case Formattable::kInt64:
    437             tInt64 = va_arg(ap, int64_t);
    438             args[i].setInt64(tInt64);
    439             break;
    440 
    441         case Formattable::kString:
    442             // For some reason, a temporary is needed
    443             stringVal = va_arg(ap, UChar*);
    444             if(stringVal){
    445                 args[i].setString(UnicodeString(stringVal));
    446             }else{
    447                 *status=U_ILLEGAL_ARGUMENT_ERROR;
    448             }
    449             break;
    450 
    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
    456             va_arg(ap, int);
    457             break;
    458 
    459         case Formattable::kObject:
    460             // Unused argument number. Read and ignore a pointer argument.
    461             va_arg(ap, void*);
    462             break;
    463 
    464         default:
    465             // Unknown/unsupported argument type.
    466             U_ASSERT(FALSE);
    467             *status=U_ILLEGAL_ARGUMENT_ERROR;
    468             break;
    469         }
    470     }
    471     UnicodeString resultStr;
    472     FieldPosition fieldPosition(FieldPosition::DONT_CARE);
    473 
    474     /* format the message */
    475     ((const MessageFormat*)fmt)->format(args,count,resultStr,fieldPosition,*status);
    476 
    477     delete[] args;
    478 
    479     if(U_FAILURE(*status)){
    480         return -1;
    481     }
    482 
    483     return resultStr.extract(result, resultLength, *status);
    484 }
    485 
    486 U_CAPI void
    487 umsg_parse( const UMessageFormat *fmt,
    488             const UChar    *source,
    489             int32_t        sourceLength,
    490             int32_t        *count,
    491             UErrorCode     *status,
    492             ...)
    493 {
    494     va_list    ap;
    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
    498 
    499     // start vararg processing
    500     va_start(ap, status);
    501 
    502     umsg_vparse(fmt,source,sourceLength,count,ap,status);
    503 
    504     // end vararg processing
    505     va_end(ap);
    506 }
    507 
    508 U_CAPI void U_EXPORT2
    509 umsg_vparse(const UMessageFormat *fmt,
    510             const UChar    *source,
    511             int32_t        sourceLength,
    512             int32_t        *count,
    513             va_list        ap,
    514             UErrorCode     *status)
    515 {
    516     //check arguments
    517     if(status==NULL||U_FAILURE(*status))
    518     {
    519         return;
    520     }
    521     if(fmt==NULL||source==NULL || sourceLength<-1 || count==NULL){
    522         *status=U_ILLEGAL_ARGUMENT_ERROR;
    523         return;
    524     }
    525     if(sourceLength==-1){
    526         sourceLength=u_strlen(source);
    527     }
    528 
    529     UnicodeString srcString(source,sourceLength);
    530     Formattable *args = ((const MessageFormat*)fmt)->parse(srcString,*count,*status);
    531     UDate *aDate;
    532     double *aDouble;
    533     UChar *aString;
    534     int32_t* aInt;
    535     int64_t* aInt64;
    536     UnicodeString temp;
    537     int len =0;
    538     // assign formattables to varargs
    539     for(int32_t i = 0; i < *count; i++) {
    540         switch(args[i].getType()) {
    541 
    542         case Formattable::kDate:
    543             aDate = va_arg(ap, UDate*);
    544             if(aDate){
    545                 *aDate = args[i].getDate();
    546             }else{
    547                 *status=U_ILLEGAL_ARGUMENT_ERROR;
    548             }
    549             break;
    550 
    551         case Formattable::kDouble:
    552             aDouble = va_arg(ap, double*);
    553             if(aDouble){
    554                 *aDouble = args[i].getDouble();
    555             }else{
    556                 *status=U_ILLEGAL_ARGUMENT_ERROR;
    557             }
    558             break;
    559 
    560         case Formattable::kLong:
    561             aInt = va_arg(ap, int32_t*);
    562             if(aInt){
    563                 *aInt = (int32_t) args[i].getLong();
    564             }else{
    565                 *status=U_ILLEGAL_ARGUMENT_ERROR;
    566             }
    567             break;
    568 
    569         case Formattable::kInt64:
    570             aInt64 = va_arg(ap, int64_t*);
    571             if(aInt64){
    572                 *aInt64 = args[i].getInt64();
    573             }else{
    574                 *status=U_ILLEGAL_ARGUMENT_ERROR;
    575             }
    576             break;
    577 
    578         case Formattable::kString:
    579             aString = va_arg(ap, UChar*);
    580             if(aString){
    581                 args[i].getString(temp);
    582                 len = temp.length();
    583                 temp.extract(0,len,aString);
    584                 aString[len]=0;
    585             }else{
    586                 *status= U_ILLEGAL_ARGUMENT_ERROR;
    587             }
    588             break;
    589 
    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]
    595             U_ASSERT(FALSE);
    596             break;
    597 
    598         // better not happen!
    599         case Formattable::kArray:
    600             U_ASSERT(FALSE);
    601             break;
    602         }
    603     }
    604 
    605     // clean up
    606     delete [] args;
    607 }
    608 
    609 #define SINGLE_QUOTE      ((UChar)0x0027)
    610 #define CURLY_BRACE_LEFT  ((UChar)0x007B)
    611 #define CURLY_BRACE_RIGHT ((UChar)0x007D)
    612 
    613 #define STATE_INITIAL 0
    614 #define STATE_SINGLE_QUOTE 1
    615 #define STATE_IN_QUOTE 2
    616 #define STATE_MSG_ELEMENT 3
    617 
    618 #define MAppend(c) if (len < destCapacity) dest[len++] = c; else len++
    619 
    620 int32_t umsg_autoQuoteApostrophe(const UChar* pattern,
    621                  int32_t patternLength,
    622                  UChar* dest,
    623                  int32_t destCapacity,
    624                  UErrorCode* ec)
    625 {
    626     int32_t state = STATE_INITIAL;
    627     int32_t braceCount = 0;
    628     int32_t len = 0;
    629 
    630     if (ec == NULL || U_FAILURE(*ec)) {
    631         return -1;
    632     }
    633 
    634     if (pattern == NULL || patternLength < -1 || (dest == NULL && destCapacity > 0)) {
    635         *ec = U_ILLEGAL_ARGUMENT_ERROR;
    636         return -1;
    637     }
    638     U_ASSERT(destCapacity >= 0);
    639 
    640     if (patternLength == -1) {
    641         patternLength = u_strlen(pattern);
    642     }
    643 
    644     for (int i = 0; i < patternLength; ++i) {
    645         UChar c = pattern[i];
    646         switch (state) {
    647         case STATE_INITIAL:
    648             switch (c) {
    649             case SINGLE_QUOTE:
    650                 state = STATE_SINGLE_QUOTE;
    651                 break;
    652             case CURLY_BRACE_LEFT:
    653                 state = STATE_MSG_ELEMENT;
    654                 ++braceCount;
    655                 break;
    656             }
    657             break;
    658 
    659         case STATE_SINGLE_QUOTE:
    660             switch (c) {
    661             case SINGLE_QUOTE:
    662                 state = STATE_INITIAL;
    663                 break;
    664             case CURLY_BRACE_LEFT:
    665             case CURLY_BRACE_RIGHT:
    666                 state = STATE_IN_QUOTE;
    667                 break;
    668             default:
    669                 MAppend(SINGLE_QUOTE);
    670                 state = STATE_INITIAL;
    671                 break;
    672             }
    673         break;
    674 
    675         case STATE_IN_QUOTE:
    676             switch (c) {
    677             case SINGLE_QUOTE:
    678                 state = STATE_INITIAL;
    679                 break;
    680             }
    681             break;
    682 
    683         case STATE_MSG_ELEMENT:
    684             switch (c) {
    685             case CURLY_BRACE_LEFT:
    686                 ++braceCount;
    687                 break;
    688             case CURLY_BRACE_RIGHT:
    689                 if (--braceCount == 0) {
    690                     state = STATE_INITIAL;
    691                 }
    692                 break;
    693             }
    694             break;
    695 
    696         default: // Never happens.
    697             break;
    698         }
    699 
    700         U_ASSERT(len >= 0);
    701         MAppend(c);
    702     }
    703 
    704     // End of scan
    705     if (state == STATE_SINGLE_QUOTE || state == STATE_IN_QUOTE) {
    706         MAppend(SINGLE_QUOTE);
    707     }
    708 
    709     return u_terminateUChars(dest, destCapacity, len, ec);
    710 }
    711 
    712 #endif /* #if !UCONFIG_NO_FORMATTING */
    713