]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/umsg.cpp
ICU-62107.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / umsg.cpp
index a4e1c33d4798bd01675574d1d11987d4633831fc..31eeacbef1f56d84fb9474734fbe11f8e6bba4b2 100644 (file)
@@ -1,12 +1,14 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /*
 *******************************************************************************
 *
-*   Copyright (C) 1999-2003, International Business Machines
+*   Copyright (C) 1999-2012, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 *
 *******************************************************************************
 *   file name:  umsg.cpp
-*   encoding:   US-ASCII
+*   encoding:   UTF-8
 *   tab size:   8 (not used)
 *   indentation:4
 *
 #include "unicode/msgfmt.h"
 #include "unicode/unistr.h"
 #include "cpputils.h"
+#include "uassert.h"
+#include "ustr_imp.h"
+
+U_NAMESPACE_BEGIN
+/**
+ * This class isolates our access to private internal methods of
+ * MessageFormat.  It is never instantiated; it exists only for C++
+ * access management.
+ */
+class MessageFormatAdapter {
+public:
+    static const Formattable::Type* getArgTypeList(const MessageFormat& m,
+                                                   int32_t& count);
+    static UBool hasArgTypeConflicts(const MessageFormat& m) {
+        return m.hasArgTypeConflicts;
+    }
+};
+const Formattable::Type*
+MessageFormatAdapter::getArgTypeList(const MessageFormat& m,
+                                     int32_t& count) {
+    return m.getArgTypeList(count);
+}
+U_NAMESPACE_END
 
 U_NAMESPACE_USE
 
@@ -215,25 +240,23 @@ umsg_open(  const UChar     *pattern,
     }
 
     UParseError tErr;
-   
     if(parseError==NULL)
     {
         parseError = &tErr;
     }
-        
-    UMessageFormat* retVal = 0;
 
     int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength);
-    
-    UnicodeString patString((patternLength == -1 ? TRUE:FALSE), pattern,len);
+    UnicodeString patString(patternLength == -1, pattern, len);
 
-    retVal = (UMessageFormat*) new MessageFormat(pattern,Locale(locale),*parseError,*status);
-    
-    if(retVal == 0) {
+    MessageFormat* retVal = new MessageFormat(patString,Locale(locale),*parseError,*status);
+    if(retVal == NULL) {
         *status = U_MEMORY_ALLOCATION_ERROR;
-        return 0;
+        return NULL;
     }
-    return retVal;
+    if (U_SUCCESS(*status) && MessageFormatAdapter::hasArgTypeConflicts(*retVal)) {
+        *status = U_ARGUMENT_TYPE_MISMATCH;
+    }
+    return (UMessageFormat*)retVal;
 }
 
 U_CAPI void U_EXPORT2
@@ -277,13 +300,13 @@ umsg_setLocale(UMessageFormat *fmt, const char* locale)
 }
 
 U_CAPI const char*  U_EXPORT2
-umsg_getLocale(UMessageFormat *fmt)
+umsg_getLocale(const UMessageFormat *fmt)
 {
     //check arguments
     if(fmt==NULL){
         return "";
     }
-    return ((MessageFormat*)fmt)->getLocale().getName();
+    return ((const MessageFormat*)fmt)->getLocale().getName();
 }
 
 U_CAPI void  U_EXPORT2
@@ -298,7 +321,7 @@ umsg_applyPattern(UMessageFormat *fmt,
     if(status ==NULL||U_FAILURE(*status)){
         return ;
     }
-    if(fmt==NULL||pattern==NULL||patternLength<-1){
+    if(fmt==NULL || (pattern==NULL && patternLength!=0) || patternLength<-1) {
         *status=U_ILLEGAL_ARGUMENT_ERROR;
         return ;
     }
@@ -306,15 +329,13 @@ umsg_applyPattern(UMessageFormat *fmt,
     if(parseError==NULL){
       parseError = &tErr;
     }
-    if(patternLength<-1){
-        patternLength=u_strlen(pattern);
-    }
 
+    // UnicodeString(pattern, -1) calls u_strlen().
     ((MessageFormat*)fmt)->applyPattern(UnicodeString(pattern,patternLength),*parseError,*status);  
 }
 
 U_CAPI int32_t  U_EXPORT2
-umsg_toPattern(UMessageFormat *fmt,
+umsg_toPattern(const UMessageFormat *fmt,
                UChar* result, 
                int32_t resultLength,
                UErrorCode* status)
@@ -335,12 +356,12 @@ umsg_toPattern(UMessageFormat *fmt,
         // otherwise, alias the destination buffer
         res.setTo(result, 0, resultLength);
     }
-    ((MessageFormat*)fmt)->toPattern(res);
+    ((const MessageFormat*)fmt)->toPattern(res);
     return res.extract(result, resultLength, *status);
 }
 
 U_CAPI int32_t
-umsg_format(    UMessageFormat *fmt,
+umsg_format(    const UMessageFormat *fmt,
                 UChar          *result,
                 int32_t        resultLength,
                 UErrorCode     *status,
@@ -364,26 +385,8 @@ umsg_format(    UMessageFormat *fmt,
     return actLen;
 }
 
-U_NAMESPACE_BEGIN
-/**
- * This class isolates our access to private internal methods of
- * MessageFormat.  It is never instantiated; it exists only for C++
- * access management.
- */
-class MessageFormatAdapter {
-public:
-    static const Formattable::Type* getArgTypeList(const MessageFormat& m,
-                                                   int32_t& count);
-};
-const Formattable::Type*
-MessageFormatAdapter::getArgTypeList(const MessageFormat& m,
-                                     int32_t& count) {
-    return m.getArgTypeList(count);
-}
-U_NAMESPACE_END
-
 U_CAPI int32_t U_EXPORT2
-umsg_vformat(   UMessageFormat *fmt,
+umsg_vformat(   const UMessageFormat *fmt,
                 UChar          *result,
                 int32_t        resultLength,
                 va_list        ap,
@@ -401,7 +404,7 @@ umsg_vformat(   UMessageFormat *fmt,
 
     int32_t count =0;
     const Formattable::Type* argTypes =
-        MessageFormatAdapter::getArgTypeList(*(MessageFormat*)fmt, count);
+        MessageFormatAdapter::getArgTypeList(*(const MessageFormat*)fmt, count);
     // Allocate at least one element.  Allocating an array of length
     // zero causes problems on some platforms (e.g. Win32).
     Formattable* args = new Formattable[count ? count : 1];
@@ -412,6 +415,7 @@ umsg_vformat(   UMessageFormat *fmt,
         UChar *stringVal;
         double tDouble=0;
         int32_t tInt =0;
+        int64_t tInt64 = 0;
         UDate tempDate = 0;
         switch(argTypes[i]) {
         case Formattable::kDate:
@@ -428,12 +432,17 @@ umsg_vformat(   UMessageFormat *fmt,
             tInt = va_arg(ap, int32_t);
             args[i].setLong(tInt);
             break;
+
+        case Formattable::kInt64:
+            tInt64 = va_arg(ap, int64_t);
+            args[i].setInt64(tInt64);
+            break;
             
         case Formattable::kString:
             // For some reason, a temporary is needed
             stringVal = va_arg(ap, UChar*);
             if(stringVal){
-                args[i].setString(stringVal);
+                args[i].setString(UnicodeString(stringVal));
             }else{
                 *status=U_ILLEGAL_ARGUMENT_ERROR;
             }
@@ -447,13 +456,23 @@ umsg_vformat(   UMessageFormat *fmt,
             va_arg(ap, int);
             break;
 
+        case Formattable::kObject:
+            // Unused argument number. Read and ignore a pointer argument.
+            va_arg(ap, void*);
+            break;
+
+        default:
+            // Unknown/unsupported argument type.
+            U_ASSERT(FALSE);
+            *status=U_ILLEGAL_ARGUMENT_ERROR;
+            break;
         }
     }
     UnicodeString resultStr;
-    FieldPosition fieldPosition(0);
+    FieldPosition fieldPosition(FieldPosition::DONT_CARE);
     
     /* format the message */
-    ((MessageFormat*)fmt)->format(args,count,resultStr,fieldPosition,*status);
+    ((const MessageFormat*)fmt)->format(args,count,resultStr,fieldPosition,*status);
 
     delete[] args;
 
@@ -465,7 +484,7 @@ umsg_vformat(   UMessageFormat *fmt,
 }
 
 U_CAPI void
-umsg_parse( UMessageFormat *fmt,
+umsg_parse( const UMessageFormat *fmt,
             const UChar    *source,
             int32_t        sourceLength,
             int32_t        *count,
@@ -487,7 +506,7 @@ umsg_parse( UMessageFormat *fmt,
 }
 
 U_CAPI void U_EXPORT2
-umsg_vparse(UMessageFormat *fmt,
+umsg_vparse(const UMessageFormat *fmt,
             const UChar    *source,
             int32_t        sourceLength,
             int32_t        *count,
@@ -508,11 +527,12 @@ umsg_vparse(UMessageFormat *fmt,
     }
 
     UnicodeString srcString(source,sourceLength);
-    Formattable *args = ((MessageFormat*)fmt)->parse(source,*count,*status);
+    Formattable *args = ((const MessageFormat*)fmt)->parse(srcString,*count,*status);
     UDate *aDate;
     double *aDouble;
     UChar *aString;
     int32_t* aInt;
+    int64_t* aInt64;
     UnicodeString temp;
     int len =0;
     // assign formattables to varargs
@@ -538,7 +558,6 @@ umsg_vparse(UMessageFormat *fmt,
             break;
 
         case Formattable::kLong:
-            
             aInt = va_arg(ap, int32_t*);
             if(aInt){
                 *aInt = (int32_t) args[i].getLong();
@@ -547,6 +566,15 @@ umsg_vparse(UMessageFormat *fmt,
             }
             break;
 
+        case Formattable::kInt64:
+            aInt64 = va_arg(ap, int64_t*);
+            if(aInt64){
+                *aInt64 = args[i].getInt64();
+            }else{
+                *status=U_ILLEGAL_ARGUMENT_ERROR;
+            }
+            break;
+
         case Formattable::kString:
             aString = va_arg(ap, UChar*);
             if(aString){
@@ -559,9 +587,17 @@ umsg_vparse(UMessageFormat *fmt,
             }
             break;
 
+        case Formattable::kObject:
+            // This will never happen because MessageFormat doesn't
+            // support kObject.  When MessageFormat is changed to
+            // understand MeasureFormats, modify this code to do the
+            // right thing. [alan]
+            U_ASSERT(FALSE);
+            break;
+
         // better not happen!
         case Formattable::kArray:
-            // DIE
+            U_ASSERT(FALSE);
             break;
         }
     }
@@ -570,4 +606,107 @@ umsg_vparse(UMessageFormat *fmt,
     delete [] args;
 }
 
+#define SINGLE_QUOTE      ((UChar)0x0027)
+#define CURLY_BRACE_LEFT  ((UChar)0x007B)
+#define CURLY_BRACE_RIGHT ((UChar)0x007D)
+
+#define STATE_INITIAL 0
+#define STATE_SINGLE_QUOTE 1
+#define STATE_IN_QUOTE 2
+#define STATE_MSG_ELEMENT 3
+
+#define MAppend(c) if (len < destCapacity) dest[len++] = c; else len++
+
+int32_t umsg_autoQuoteApostrophe(const UChar* pattern, 
+                 int32_t patternLength,
+                 UChar* dest,
+                 int32_t destCapacity,
+                 UErrorCode* ec)
+{
+    int32_t state = STATE_INITIAL;
+    int32_t braceCount = 0;
+    int32_t len = 0;
+
+    if (ec == NULL || U_FAILURE(*ec)) {
+        return -1;
+    }
+
+    if (pattern == NULL || patternLength < -1 || (dest == NULL && destCapacity > 0)) {
+        *ec = U_ILLEGAL_ARGUMENT_ERROR;
+        return -1;
+    }
+    U_ASSERT(destCapacity >= 0);
+
+    if (patternLength == -1) {
+        patternLength = u_strlen(pattern);
+    }
+
+    for (int i = 0; i < patternLength; ++i) {
+        UChar c = pattern[i];
+        switch (state) {
+        case STATE_INITIAL:
+            switch (c) {
+            case SINGLE_QUOTE:
+                state = STATE_SINGLE_QUOTE;
+                break;
+            case CURLY_BRACE_LEFT:
+                state = STATE_MSG_ELEMENT;
+                ++braceCount;
+                break;
+            }
+            break;
+
+        case STATE_SINGLE_QUOTE:
+            switch (c) {
+            case SINGLE_QUOTE:
+                state = STATE_INITIAL;
+                break;
+            case CURLY_BRACE_LEFT:
+            case CURLY_BRACE_RIGHT:
+                state = STATE_IN_QUOTE;
+                break;
+            default:
+                MAppend(SINGLE_QUOTE);
+                state = STATE_INITIAL;
+                break;
+            }
+        break;
+
+        case STATE_IN_QUOTE:
+            switch (c) {
+            case SINGLE_QUOTE:
+                state = STATE_INITIAL;
+                break;
+            }
+            break;
+
+        case STATE_MSG_ELEMENT:
+            switch (c) {
+            case CURLY_BRACE_LEFT:
+                ++braceCount;
+                break;
+            case CURLY_BRACE_RIGHT:
+                if (--braceCount == 0) {
+                    state = STATE_INITIAL;
+                }
+                break;
+            }
+            break;
+
+        default: // Never happens.
+            break;
+        }
+
+        U_ASSERT(len >= 0);
+        MAppend(c);
+    }
+
+    // End of scan
+    if (state == STATE_SINGLE_QUOTE || state == STATE_IN_QUOTE) {
+        MAppend(SINGLE_QUOTE);
+    }
+
+    return u_terminateUChars(dest, destCapacity, len, ec);
+}
+
 #endif /* #if !UCONFIG_NO_FORMATTING */