intl/icu/source/i18n/umsg.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /*
     2 *******************************************************************************
     3 *
     4 *   Copyright (C) 1999-2012, 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 */
    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"
    31 #include "cpputils.h"
    32 #include "uassert.h"
    33 #include "ustr_imp.h"
    35 U_NAMESPACE_BEGIN
    36 /**
    37  * This class isolates our access to private internal methods of
    38  * MessageFormat.  It is never instantiated; it exists only for C++
    39  * access management.
    40  */
    41 class MessageFormatAdapter {
    42 public:
    43     static const Formattable::Type* getArgTypeList(const MessageFormat& m,
    44                                                    int32_t& count);
    45     static UBool hasArgTypeConflicts(const MessageFormat& m) {
    46         return m.hasArgTypeConflicts;
    47     }
    48 };
    49 const Formattable::Type*
    50 MessageFormatAdapter::getArgTypeList(const MessageFormat& m,
    51                                      int32_t& count) {
    52     return m.getArgTypeList(count);
    53 }
    54 U_NAMESPACE_END
    56 U_NAMESPACE_USE
    58 U_CAPI int32_t
    59 u_formatMessage(const char  *locale,
    60                 const UChar *pattern,
    61                 int32_t     patternLength,
    62                 UChar       *result,
    63                 int32_t     resultLength,
    64                 UErrorCode  *status,
    65                 ...)
    66 {
    67     va_list    ap;
    68     int32_t actLen;        
    69     //argument checking defered to subsequent method calls
    70     // start vararg processing
    71     va_start(ap, status);
    73     actLen = u_vformatMessage(locale,pattern,patternLength,result,resultLength,ap,status);
    74     // end vararg processing
    75     va_end(ap);
    77     return actLen;
    78 }
    80 U_CAPI int32_t U_EXPORT2
    81 u_vformatMessage(   const char  *locale,
    82                     const UChar *pattern,
    83                     int32_t     patternLength,
    84                     UChar       *result,
    85                     int32_t     resultLength,
    86                     va_list     ap,
    87                     UErrorCode  *status)
    89 {
    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);
    93     umsg_close(fmt);
    94     return retVal;
    95 }
    97 U_CAPI int32_t
    98 u_formatMessageWithError(const char *locale,
    99                         const UChar *pattern,
   100                         int32_t     patternLength,
   101                         UChar       *result,
   102                         int32_t     resultLength,
   103                         UParseError *parseError,
   104                         UErrorCode  *status,
   105                         ...)
   106 {
   107     va_list    ap;
   108     int32_t actLen;
   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
   116     va_end(ap);
   117     return actLen;
   118 }
   120 U_CAPI int32_t U_EXPORT2
   121 u_vformatMessageWithError(  const char  *locale,
   122                             const UChar *pattern,
   123                             int32_t     patternLength,
   124                             UChar       *result,
   125                             int32_t     resultLength,
   126                             UParseError *parseError,
   127                             va_list     ap,
   128                             UErrorCode  *status)
   130 {
   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);
   134     umsg_close(fmt);
   135     return retVal;
   136 }
   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
   143 U_CAPI void
   144 u_parseMessage( const char   *locale,
   145                 const UChar  *pattern,
   146                 int32_t      patternLength,
   147                 const UChar  *source,
   148                 int32_t      sourceLength,
   149                 UErrorCode   *status,
   150                 ...)
   151 {
   152     va_list    ap;
   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
   160     va_end(ap);
   161 }
   163 U_CAPI void U_EXPORT2
   164 u_vparseMessage(const char  *locale,
   165                 const UChar *pattern,
   166                 int32_t     patternLength,
   167                 const UChar *source,
   168                 int32_t     sourceLength,
   169                 va_list     ap,
   170                 UErrorCode  *status)
   171 {
   172     //argument checking defered to subsequent method calls
   173     UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,NULL,status);
   174     int32_t count = 0;
   175     umsg_vparse(fmt,source,sourceLength,&count,ap,status);
   176     umsg_close(fmt);
   177 }
   179 U_CAPI void
   180 u_parseMessageWithError(const char  *locale,
   181                         const UChar *pattern,
   182                         int32_t     patternLength,
   183                         const UChar *source,
   184                         int32_t     sourceLength,
   185                         UParseError *error,
   186                         UErrorCode  *status,
   187                         ...)
   188 {
   189     va_list    ap;
   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
   198     va_end(ap);
   199 }
   200 U_CAPI void U_EXPORT2
   201 u_vparseMessageWithError(const char  *locale,
   202                          const UChar *pattern,
   203                          int32_t     patternLength,
   204                          const UChar *source,
   205                          int32_t     sourceLength,
   206                          va_list     ap,
   207                          UParseError *error,
   208                          UErrorCode* status)
   209 {
   210     //argument checking defered to subsequent method calls
   211     UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,error,status);
   212     int32_t count = 0;
   213     umsg_vparse(fmt,source,sourceLength,&count,ap,status);
   214     umsg_close(fmt);
   215 }
   216 //////////////////////////////////////////////////////////////////////////////////
   217 //
   218 //  Message format C API
   219 //
   220 /////////////////////////////////////////////////////////////////////////////////
   223 U_CAPI UMessageFormat* U_EXPORT2
   224 umsg_open(  const UChar     *pattern,
   225             int32_t         patternLength,
   226             const  char     *locale,
   227             UParseError     *parseError,
   228             UErrorCode      *status)
   229 {
   230     //check arguments
   231     if(status==NULL || U_FAILURE(*status))
   232     {
   233       return 0;
   234     }
   235     if(pattern==NULL||patternLength<-1){
   236         *status=U_ILLEGAL_ARGUMENT_ERROR;
   237         return 0;
   238     }
   240     UParseError tErr;
   241     if(parseError==NULL)
   242     {
   243         parseError = &tErr;
   244     }
   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);
   250     if(retVal == NULL) {
   251         *status = U_MEMORY_ALLOCATION_ERROR;
   252         return NULL;
   253     }
   254     if (U_SUCCESS(*status) && MessageFormatAdapter::hasArgTypeConflicts(*retVal)) {
   255         *status = U_ARGUMENT_TYPE_MISMATCH;
   256     }
   257     return (UMessageFormat*)retVal;
   258 }
   260 U_CAPI void U_EXPORT2
   261 umsg_close(UMessageFormat* format)
   262 {
   263     //check arguments
   264     if(format==NULL){
   265         return;
   266     }
   267     delete (MessageFormat*) format;
   268 }
   270 U_CAPI UMessageFormat U_EXPORT2
   271 umsg_clone(const UMessageFormat *fmt,
   272            UErrorCode *status)
   273 {
   274     //check arguments
   275     if(status==NULL || U_FAILURE(*status)){
   276         return NULL;
   277     }
   278     if(fmt==NULL){
   279         *status = U_ILLEGAL_ARGUMENT_ERROR;
   280         return NULL;
   281     }
   282     UMessageFormat retVal = (UMessageFormat)((MessageFormat*)fmt)->clone();
   283     if(retVal == 0) {
   284         *status = U_MEMORY_ALLOCATION_ERROR;
   285         return 0;
   286     }
   287     return retVal;    
   288 }
   290 U_CAPI void  U_EXPORT2
   291 umsg_setLocale(UMessageFormat *fmt, const char* locale)
   292 {
   293     //check arguments
   294     if(fmt==NULL){
   295         return;
   296     }
   297     ((MessageFormat*)fmt)->setLocale(Locale(locale));   
   298 }
   300 U_CAPI const char*  U_EXPORT2
   301 umsg_getLocale(const UMessageFormat *fmt)
   302 {
   303     //check arguments
   304     if(fmt==NULL){
   305         return "";
   306     }
   307     return ((const MessageFormat*)fmt)->getLocale().getName();
   308 }
   310 U_CAPI void  U_EXPORT2
   311 umsg_applyPattern(UMessageFormat *fmt,
   312                            const UChar* pattern,
   313                            int32_t patternLength,
   314                            UParseError* parseError,
   315                            UErrorCode* status)
   316 {
   317     //check arguments
   318     UParseError tErr;
   319     if(status ==NULL||U_FAILURE(*status)){
   320         return ;
   321     }
   322     if(fmt==NULL||pattern==NULL||patternLength<-1){
   323         *status=U_ILLEGAL_ARGUMENT_ERROR;
   324         return ;
   325     }
   327     if(parseError==NULL){
   328       parseError = &tErr;
   329     }
   330     if(patternLength<-1){
   331         patternLength=u_strlen(pattern);
   332     }
   334     ((MessageFormat*)fmt)->applyPattern(UnicodeString(pattern,patternLength),*parseError,*status);  
   335 }
   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     }
   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 }
   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
   377     // start vararg processing
   378     va_start(ap, status);
   380     actLen = umsg_vformat(fmt,result,resultLength,ap,status);
   382     // end vararg processing
   383     va_end(ap);
   385     return actLen;
   386 }
   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     }
   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];
   412     // iterate through the vararg list, and get the arguments out
   413     for(int32_t i = 0; i < count; ++i) {
   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;
   426         case Formattable::kDouble:
   427             tDouble =va_arg(ap, double);
   428             args[i].setDouble(tDouble);
   429             break;
   431         case Formattable::kLong:
   432             tInt = va_arg(ap, int32_t);
   433             args[i].setLong(tInt);
   434             break;
   436         case Formattable::kInt64:
   437             tInt64 = va_arg(ap, int64_t);
   438             args[i].setInt64(tInt64);
   439             break;
   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;
   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;
   459         case Formattable::kObject:
   460             // Unused argument number. Read and ignore a pointer argument.
   461             va_arg(ap, void*);
   462             break;
   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(0);
   474     /* format the message */
   475     ((const MessageFormat*)fmt)->format(args,count,resultStr,fieldPosition,*status);
   477     delete[] args;
   479     if(U_FAILURE(*status)){
   480         return -1;
   481     }
   483     return resultStr.extract(result, resultLength, *status);
   484 }
   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
   499     // start vararg processing
   500     va_start(ap, status);
   502     umsg_vparse(fmt,source,sourceLength,count,ap,status);
   504     // end vararg processing
   505     va_end(ap);
   506 }
   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     }
   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()) {
   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;
   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;
   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;
   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;
   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;
   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;
   598         // better not happen!
   599         case Formattable::kArray:
   600             U_ASSERT(FALSE);
   601             break;
   602         }
   603     }
   605     // clean up
   606     delete [] args;
   607 }
   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,
   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;
   630     if (ec == NULL || U_FAILURE(*ec)) {
   631         return -1;
   632     }
   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);
   640     if (patternLength == -1) {
   641         patternLength = u_strlen(pattern);
   642     }
   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;
   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;
   675         case STATE_IN_QUOTE:
   676             switch (c) {
   677             case SINGLE_QUOTE:
   678                 state = STATE_INITIAL;
   679                 break;
   680             }
   681             break;
   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;
   696         default: // Never happens.
   697             break;
   698         }
   700         U_ASSERT(len >= 0);
   701         MAppend(c);
   702     }
   704     // End of scan
   705     if (state == STATE_SINGLE_QUOTE || state == STATE_IN_QUOTE) {
   706         MAppend(SINGLE_QUOTE);
   707     }
   709     return u_terminateUChars(dest, destCapacity, len, ec);
   710 }
   712 #endif /* #if !UCONFIG_NO_FORMATTING */

mercurial