/*
******************************************************************************
-* 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)
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" */
// 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
}
// 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
// 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;
// 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
* @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;
// 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
}
void
-NFRule::appendRuleText(UnicodeString& result) const
+NFRule::_appendRuleText(UnicodeString& result) const
{
switch (getType()) {
case kNegativeNumberRule: result.append(gMinusX); break;
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
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
fprintf(stderr, "doParse %x ", this);
{
UnicodeString rt;
- appendRuleText(rt);
+ _appendRuleText(rt);
dumpUS(stderr, rt);
}
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
{
// 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"
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;
* 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.
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;
// 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;
* 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) {
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);