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