/*
******************************************************************************
-* Copyright (C) 1997-2004, International Business Machines
+* Copyright (C) 1997-2008, International Business Machines
* Corporation and others. All Rights Reserved.
******************************************************************************
* file name: nfrule.cpp
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" */
// 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
}
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);