]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/nfrule.cpp
ICU-461.13.tar.gz
[apple/icu.git] / icuSources / i18n / nfrule.cpp
index 438dfcaccf8ab40734acdbcd7c674d03aa1e55ab..76a2ad2905d89ff93ed2c8e21798913a22949880 100644 (file)
@@ -1,6 +1,6 @@
 /*
 ******************************************************************************
-*   Copyright (C) 1997-2001, International Business Machines
+*   Copyright (C) 1997-2008, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 ******************************************************************************
 *   file name:  nfrule.cpp
 #include "nfrlist.h"
 #include "nfsubs.h"
 
-#include "uprops.h"
+#include "util.h"
 
 U_NAMESPACE_BEGIN
 
-extern const UChar* CSleftBracket;
-extern const UChar* CSrightBracket;
-
 NFRule::NFRule(const RuleBasedNumberFormat* _rbnf)
   : baseValue((int32_t)0)
   , radix(0)
@@ -57,10 +54,11 @@ static const UChar gNine = 0x0039;
 static const UChar gSpace = 0x0020;
 static const UChar gSlash = 0x002f;
 static const UChar gGreaterThan = 0x003e;
+static const UChar gLessThan = 0x003c;
 static const UChar gComma = 0x002c;
 static const UChar gDot = 0x002e;
 static const UChar gTick = 0x0027;
-static const UChar gMinus = 0x002d;
+//static const UChar gMinus = 0x002d;
 static const UChar gSemicolon = 0x003b;
 
 static const UChar gMinusX[] =                  {0x2D, 0x78, 0};    /* "-x" */
@@ -228,7 +226,7 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status)
     // it's omitted, just set the base value to 0.
     int32_t p = description.indexOf(gColon);
     if (p == -1) {
-        setBaseValue((int32_t)0);
+        setBaseValue((int32_t)0, status);
     } else {
         // copy the descriptor out into its own string and strip it,
         // along with any trailing whitespace, out of the original
@@ -291,7 +289,7 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status)
             }
 
             // we have the base value, so set it
-            setBaseValue(val);
+            setBaseValue(val, status);
 
             // if we stopped the previous loop on a slash, we're
             // now parsing the rule's radix.  Again, accumulate digits
@@ -321,7 +319,7 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status)
 
                 // tempValue now contain's the rule's radix.  Set it
                 // accordingly, and recalculate the rule's exponent
-                radix = (int16_t)val;
+                radix = (int32_t)val;
                 if (radix == 0) {
                     // throw new IllegalArgumentException("Rule can't have radix of 0");
                     status = U_PARSE_ERROR;
@@ -423,8 +421,17 @@ NFRule::extractSubstitution(const NFRuleSet* ruleSet,
         // otherwise the substitution token ends with the same character
         // it began with
     } else {
-        subEnd = ruleText.indexOf(ruleText.charAt(subStart), subStart + 1);
-    }
+        UChar c = ruleText.charAt(subStart);
+        subEnd = ruleText.indexOf(c, subStart + 1);
+        // special case for '<%foo<<'
+        if (c == gLessThan && subEnd != -1 && subEnd < ruleText.length() - 1 && ruleText.charAt(subEnd+1) == c) {
+            // ordinals use "=#,##0==%abbrev=" as their rule.  Notice that the '==' in the middle
+            // occurs because of the juxtaposition of two different rules.  The check for '<' is a hack
+            // to get around this.  Having the duplicate at the front would cause problems with
+            // rules like "<<%" to format, say, percents...
+            ++subEnd;
+        }
+   }
 
     // if we don't find the end of the token (i.e., if we're on a single,
     // unmatched token character), create a null substitution positioned
@@ -456,7 +463,7 @@ NFRule::extractSubstitution(const NFRuleSet* ruleSet,
  * @param The new base value for the rule.
  */
 void
-NFRule::setBaseValue(int64_t newBaseValue)
+NFRule::setBaseValue(int64_t newBaseValue, UErrorCode& status)
 {
     // set the base value
     baseValue = newBaseValue;
@@ -475,10 +482,10 @@ NFRule::setBaseValue(int64_t newBaseValue)
         // has substitutions, and some substitutions hold on to copies
         // of the rule's divisor.  Fix their copies of the divisor.
         if (sub1 != NULL) {
-            sub1->setDivisor(radix, exponent);
+            sub1->setDivisor(radix, exponent, status);
         }
         if (sub2 != NULL) {
-            sub2->setDivisor(radix, exponent);
+            sub2->setDivisor(radix, exponent, status);
         }
 
         // if this is a special rule, its radix and exponent are basically
@@ -572,7 +579,7 @@ static void util_append64(UnicodeString& result, int64_t n)
 }
 
 void
-NFRule::appendRuleText(UnicodeString& result) const
+NFRule::_appendRuleText(UnicodeString& result) const
 {
     switch (getType()) {
     case kNegativeNumberRule: result.append(gMinusX); break;
@@ -736,10 +743,12 @@ NFRule::shouldRollBack(double number) const
 static void dumpUS(FILE* f, const UnicodeString& us) {
   int len = us.length();
   char* buf = (char *)uprv_malloc((len+1)*sizeof(char)); //new char[len+1];
-  us.extract(0, len, buf);
-  buf[len] = 0;
-  fprintf(f, "%s", buf);
-  uprv_free(buf); //delete[] buf;
+  if (buf != NULL) {
+         us.extract(0, len, buf);
+         buf[len] = 0;
+         fprintf(f, "%s", buf);
+         uprv_free(buf); //delete[] buf;
+  }
 }
 #endif
 
@@ -748,7 +757,8 @@ NFRule::doParse(const UnicodeString& text,
                 ParsePosition& parsePosition,
                 UBool isFractionRule,
                 double upperBound,
-                Formattable& resVal) const
+                Formattable& resVal,
+                UBool isDecimFmtParseable) const
 {
     // internally we operate on a copy of the string being parsed
     // (because we're going to change it) and use our own ParsePosition
@@ -766,7 +776,7 @@ NFRule::doParse(const UnicodeString& text,
     fprintf(stderr, "doParse %x ", this);
     {
         UnicodeString rt;
-        appendRuleText(rt);
+        _appendRuleText(rt);
         dumpUS(stderr, rt);
     }
 
@@ -790,6 +800,17 @@ NFRule::doParse(const UnicodeString& text,
         return TRUE;
     }
 
+    // Detect when this rule's main job is to parse a decimal format and we're not
+    // supposed to.
+    if (!isDecimFmtParseable) {
+       // The following tries to detect a rule like "x.x: =#,##0.#=;"
+        if ( sub1->isDecimalFormatSubstitutionOnly() && sub2->isRuleSetSubstitutionOnly() ) {
+            parsePosition.setErrorIndex(pp.getErrorIndex());
+            resVal.setLong(0);
+            return TRUE;
+        }
+    }
+
     // this is the fun part.  The basic guts of the rule-matching
     // logic is matchToDelimiter(), which is called twice.  The first
     // time it searches the input string for the rule text BETWEEN
@@ -939,11 +960,15 @@ NFRule::stripPrefix(UnicodeString& text, const UnicodeString& prefix, ParsePosit
 {
     // if the prefix text is empty, dump out without doing anything
     if (prefix.length() != 0) {
+       UErrorCode status = U_ZERO_ERROR;
         // use prefixLength() to match the beginning of
         // "text" against "prefix".  This function returns the
         // number of characters from "text" that matched (or 0 if
         // we didn't match the whole prefix)
-        int32_t pfl = prefixLength(text, prefix);
+        int32_t pfl = prefixLength(text, prefix, status);
+        if (U_FAILURE(status)) { // Memory allocation error.
+               return;
+        }
         if (pfl != 0) {
             // if we got a successful match, update the parse position
             // and strip the prefix off of "text"
@@ -991,11 +1016,15 @@ NFRule::matchToDelimiter(const UnicodeString& text,
                          const NFSubstitution* sub,
                          double upperBound) const
 {
+       UErrorCode status = U_ZERO_ERROR;
     // if "delimiter" contains real (i.e., non-ignorable) text, search
     // it for "delimiter" beginning at "start".  If that succeeds, then
     // use "sub"'s doParse() method to match the text before the
     // instance of "delimiter" we just found.
-    if (!allIgnorable(delimiter)) {
+    if (!allIgnorable(delimiter, status)) {
+       if (U_FAILURE(status)) { //Memory allocation error.
+               return 0;
+       }
         ParsePosition tempPP;
         Formattable result;
 
@@ -1103,7 +1132,7 @@ NFRule::matchToDelimiter(const UnicodeString& text,
 * text with a collator).  If there's no match, this is 0.
 */
 int32_t
-NFRule::prefixLength(const UnicodeString& str, const UnicodeString& prefix) const
+NFRule::prefixLength(const UnicodeString& str, const UnicodeString& prefix, UErrorCode& status) const
 {
     // if we're looking for an empty prefix, it obviously matches
     // zero characters.  Just go ahead and return 0.
@@ -1124,6 +1153,14 @@ NFRule::prefixLength(const UnicodeString& str, const UnicodeString& prefix) cons
         RuleBasedCollator* collator = (RuleBasedCollator*)formatter->getCollator();
         CollationElementIterator* strIter = collator->createCollationElementIterator(str);
         CollationElementIterator* prefixIter = collator->createCollationElementIterator(prefix);
+        // Check for memory allocation error.
+        if (collator == NULL || strIter == NULL || prefixIter == NULL) {
+               delete collator;
+               delete strIter;
+               delete prefixIter;
+               status = U_MEMORY_ALLOCATION_ERROR;
+               return 0;
+        }
 
         UErrorCode err = U_ZERO_ERROR;
 
@@ -1322,9 +1359,13 @@ NFRule::findText(const UnicodeString& str,
         // slow, but it will locate the key and tell use how long the
         // matching text was.
         UnicodeString temp;
+        UErrorCode status = U_ZERO_ERROR;
         while (p < str.length() && keyLen == 0) {
             temp.setTo(str, p, str.length() - p);
-            keyLen = prefixLength(temp, key);
+            keyLen = prefixLength(temp, key, status);
+            if (U_FAILURE(status)) {
+               break;
+            }
             if (keyLen != 0) {
                 *length = keyLen;
                 return p;
@@ -1399,7 +1440,7 @@ NFRule::findText(const UnicodeString& str,
 * ignorable at the primary-order level.  false otherwise.
 */
 UBool
-NFRule::allIgnorable(const UnicodeString& str) const
+NFRule::allIgnorable(const UnicodeString& str, UErrorCode& status) const
 {
     // if the string is empty, we can just return true
     if (str.length() == 0) {
@@ -1413,6 +1454,14 @@ NFRule::allIgnorable(const UnicodeString& str) const
     if (formatter->isLenient()) {
         RuleBasedCollator* collator = (RuleBasedCollator*)(formatter->getCollator());
         CollationElementIterator* iter = collator->createCollationElementIterator(str);
+        
+        // Memory allocation error check.
+        if (collator == NULL || iter == NULL) {
+               delete collator;
+               delete iter;
+               status = U_MEMORY_ALLOCATION_ERROR;
+               return FALSE;
+        }
 
         UErrorCode err = U_ZERO_ERROR;
         int32_t o = iter->next(err);