Home | History | Annotate | Download | only in i18n
      1 // Copyright (C) 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:   US-ASCII
     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<-1){
    325         *status=U_ILLEGAL_ARGUMENT_ERROR;
    326         return ;
    327     }
    328 
    329     if(parseError==NULL){
    330       parseError = &tErr;
    331     }
    332     if(patternLength<-1){
    333         patternLength=u_strlen(pattern);
    334     }
    335 
    336     ((MessageFormat*)fmt)->applyPattern(UnicodeString(pattern,patternLength),*parseError,*status);
    337 }
    338 
    339 U_CAPI int32_t  U_EXPORT2
    340 umsg_toPattern(const UMessageFormat *fmt,
    341                UChar* result,
    342                int32_t resultLength,
    343                UErrorCode* status)
    344 {
    345     //check arguments
    346     if(status ==NULL||U_FAILURE(*status)){
    347         return -1;
    348     }
    349     if(fmt==NULL||resultLength<0 || (resultLength>0 && result==0)){
    350         *status=U_ILLEGAL_ARGUMENT_ERROR;
    351         return -1;
    352     }
    353 
    354 
    355     UnicodeString res;
    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);
    360     }
    361     ((const MessageFormat*)fmt)->toPattern(res);
    362     return res.extract(result, resultLength, *status);
    363 }
    364 
    365 U_CAPI int32_t
    366 umsg_format(    const UMessageFormat *fmt,
    367                 UChar          *result,
    368                 int32_t        resultLength,
    369                 UErrorCode     *status,
    370                 ...)
    371 {
    372     va_list    ap;
    373     int32_t actLen;
    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
    377 
    378 
    379     // start vararg processing
    380     va_start(ap, status);
    381 
    382     actLen = umsg_vformat(fmt,result,resultLength,ap,status);
    383 
    384     // end vararg processing
    385     va_end(ap);
    386 
    387     return actLen;
    388 }
    389 
    390 U_CAPI int32_t U_EXPORT2
    391 umsg_vformat(   const UMessageFormat *fmt,
    392                 UChar          *result,
    393                 int32_t        resultLength,
    394                 va_list        ap,
    395                 UErrorCode     *status)
    396 {
    397     //check arguments
    398     if(status==0 || U_FAILURE(*status))
    399     {
    400         return -1;
    401     }
    402     if(fmt==NULL||resultLength<0 || (resultLength>0 && result==0)) {
    403         *status=U_ILLEGAL_ARGUMENT_ERROR;
    404         return -1;
    405     }
    406 
    407     int32_t count =0;
    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];
    413 
    414     // iterate through the vararg list, and get the arguments out
    415     for(int32_t i = 0; i < count; ++i) {
    416 
    417         UChar *stringVal;
    418         double tDouble=0;
    419         int32_t tInt =0;
    420         int64_t tInt64 = 0;
    421         UDate tempDate = 0;
    422         switch(argTypes[i]) {
    423         case Formattable::kDate:
    424             tempDate = va_arg(ap, UDate);
    425             args[i].setDate(tempDate);
    426             break;
    427 
    428         case Formattable::kDouble:
    429             tDouble =va_arg(ap, double);
    430             args[i].setDouble(tDouble);
    431             break;
    432 
    433         case Formattable::kLong:
    434             tInt = va_arg(ap, int32_t);
    435             args[i].setLong(tInt);
    436             break;
    437 
    438         case Formattable::kInt64:
    439             tInt64 = va_arg(ap, int64_t);
    440             args[i].setInt64(tInt64);
    441             break;
    442 
    443         case Formattable::kString:
    444             // For some reason, a temporary is needed
    445             stringVal = va_arg(ap, UChar*);
    446             if(stringVal){
    447                 args[i].setString(UnicodeString(stringVal));
    448             }else{
    449                 *status=U_ILLEGAL_ARGUMENT_ERROR;
    450             }
    451             break;
    452 
    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
    458             va_arg(ap, int);
    459             break;
    460 
    461         case Formattable::kObject:
    462             // Unused argument number. Read and ignore a pointer argument.
    463             va_arg(ap, void*);
    464             break;
    465 
    466         default:
    467             // Unknown/unsupported argument type.
    468             U_ASSERT(FALSE);
    469             *status=U_ILLEGAL_ARGUMENT_ERROR;
    470             break;
    471         }
    472     }
    473     UnicodeString resultStr;
    474     FieldPosition fieldPosition(FieldPosition::DONT_CARE);
    475 
    476     /* format the message */
    477     ((const MessageFormat*)fmt)->format(args,count,resultStr,fieldPosition,*status);
    478 
    479     delete[] args;
    480 
    481     if(U_FAILURE(*status)){
    482         return -1;
    483     }
    484 
    485     return resultStr.extract(result, resultLength, *status);
    486 }
    487 
    488 U_CAPI void
    489 umsg_parse( const UMessageFormat *fmt,
    490             const UChar    *source,
    491             int32_t        sourceLength,
    492             int32_t        *count,
    493             UErrorCode     *status,
    494             ...)
    495 {
    496     va_list    ap;
    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
    500 
    501     // start vararg processing
    502     va_start(ap, status);
    503 
    504     umsg_vparse(fmt,source,sourceLength,count,ap,status);
    505 
    506     // end vararg processing
    507     va_end(ap);
    508 }
    509 
    510 U_CAPI void U_EXPORT2
    511 umsg_vparse(const UMessageFormat *fmt,
    512             const UChar    *source,
    513             int32_t        sourceLength,
    514             int32_t        *count,
    515             va_list        ap,
    516             UErrorCode     *status)
    517 {
    518     //check arguments
    519     if(status==NULL||U_FAILURE(*status))
    520     {
    521         return;
    522     }
    523     if(fmt==NULL||source==NULL || sourceLength<-1 || count==NULL){
    524         *status=U_ILLEGAL_ARGUMENT_ERROR;
    525         return;
    526     }
    527     if(sourceLength==-1){
    528         sourceLength=u_strlen(source);
    529     }
    530 
    531     UnicodeString srcString(source,sourceLength);
    532     Formattable *args = ((const MessageFormat*)fmt)->parse(srcString,*count,*status);
    533     UDate *aDate;
    534     double *aDouble;
    535     UChar *aString;
    536     int32_t* aInt;
    537     int64_t* aInt64;
    538     UnicodeString temp;
    539     int len =0;
    540     // assign formattables to varargs
    541     for(int32_t i = 0; i < *count; i++) {
    542         switch(args[i].getType()) {
    543 
    544         case Formattable::kDate:
    545             aDate = va_arg(ap, UDate*);
    546             if(aDate){
    547                 *aDate = args[i].getDate();
    548             }else{
    549                 *status=U_ILLEGAL_ARGUMENT_ERROR;
    550             }
    551             break;
    552 
    553         case Formattable::kDouble:
    554             aDouble = va_arg(ap, double*);
    555             if(aDouble){
    556                 *aDouble = args[i].getDouble();
    557             }else{
    558                 *status=U_ILLEGAL_ARGUMENT_ERROR;
    559             }
    560             break;
    561 
    562         case Formattable::kLong:
    563             aInt = va_arg(ap, int32_t*);
    564             if(aInt){
    565                 *aInt = (int32_t) args[i].getLong();
    566             }else{
    567                 *status=U_ILLEGAL_ARGUMENT_ERROR;
    568             }
    569             break;
    570 
    571         case Formattable::kInt64:
    572             aInt64 = va_arg(ap, int64_t*);
    573             if(aInt64){
    574                 *aInt64 = args[i].getInt64();
    575             }else{
    576                 *status=U_ILLEGAL_ARGUMENT_ERROR;
    577             }
    578             break;
    579 
    580         case Formattable::kString:
    581             aString = va_arg(ap, UChar*);
    582             if(aString){
    583                 args[i].getString(temp);
    584                 len = temp.length();
    585                 temp.extract(0,len,aString);
    586                 aString[len]=0;
    587             }else{
    588                 *status= U_ILLEGAL_ARGUMENT_ERROR;
    589             }
    590             break;
    591 
    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]
    597             U_ASSERT(FALSE);
    598             break;
    599 
    600         // better not happen!
    601         case Formattable::kArray:
    602             U_ASSERT(FALSE);
    603             break;
    604         }
    605     }
    606 
    607     // clean up
    608     delete [] args;
    609 }
    610 
    611 #define SINGLE_QUOTE      ((UChar)0x0027)
    612 #define CURLY_BRACE_LEFT  ((UChar)0x007B)
    613 #define CURLY_BRACE_RIGHT ((UChar)0x007D)
    614 
    615 #define STATE_INITIAL 0
    616 #define STATE_SINGLE_QUOTE 1
    617 #define STATE_IN_QUOTE 2
    618 #define STATE_MSG_ELEMENT 3
    619 
    620 #define MAppend(c) if (len < destCapacity) dest[len++] = c; else len++
    621 
    622 int32_t umsg_autoQuoteApostrophe(const UChar* pattern,
    623                  int32_t patternLength,
    624                  UChar* dest,
    625                  int32_t destCapacity,
    626                  UErrorCode* ec)
    627 {
    628     int32_t state = STATE_INITIAL;
    629     int32_t braceCount = 0;
    630     int32_t len = 0;
    631 
    632     if (ec == NULL || U_FAILURE(*ec)) {
    633         return -1;
    634     }
    635 
    636     if (pattern == NULL || patternLength < -1 || (dest == NULL && destCapacity > 0)) {
    637         *ec = U_ILLEGAL_ARGUMENT_ERROR;
    638         return -1;
    639     }
    640     U_ASSERT(destCapacity >= 0);
    641 
    642     if (patternLength == -1) {
    643         patternLength = u_strlen(pattern);
    644     }
    645 
    646     for (int i = 0; i < patternLength; ++i) {
    647         UChar c = pattern[i];
    648         switch (state) {
    649         case STATE_INITIAL:
    650             switch (c) {
    651             case SINGLE_QUOTE:
    652                 state = STATE_SINGLE_QUOTE;
    653                 break;
    654             case CURLY_BRACE_LEFT:
    655                 state = STATE_MSG_ELEMENT;
    656                 ++braceCount;
    657                 break;
    658             }
    659             break;
    660 
    661         case STATE_SINGLE_QUOTE:
    662             switch (c) {
    663             case SINGLE_QUOTE:
    664                 state = STATE_INITIAL;
    665                 break;
    666             case CURLY_BRACE_LEFT:
    667             case CURLY_BRACE_RIGHT:
    668                 state = STATE_IN_QUOTE;
    669                 break;
    670             default:
    671                 MAppend(SINGLE_QUOTE);
    672                 state = STATE_INITIAL;
    673                 break;
    674             }
    675         break;
    676 
    677         case STATE_IN_QUOTE:
    678             switch (c) {
    679             case SINGLE_QUOTE:
    680                 state = STATE_INITIAL;
    681                 break;
    682             }
    683             break;
    684 
    685         case STATE_MSG_ELEMENT:
    686             switch (c) {
    687             case CURLY_BRACE_LEFT:
    688                 ++braceCount;
    689                 break;
    690             case CURLY_BRACE_RIGHT:
    691                 if (--braceCount == 0) {
    692                     state = STATE_INITIAL;
    693                 }
    694                 break;
    695             }
    696             break;
    697 
    698         default: // Never happens.
    699             break;
    700         }
    701 
    702         U_ASSERT(len >= 0);
    703         MAppend(c);
    704     }
    705 
    706     // End of scan
    707     if (state == STATE_SINGLE_QUOTE || state == STATE_IN_QUOTE) {
    708         MAppend(SINGLE_QUOTE);
    709     }
    710 
    711     return u_terminateUChars(dest, destCapacity, len, ec);
    712 }
    713 
    714 #endif /* #if !UCONFIG_NO_FORMATTING */
    715