/*
******************************************************************************
-* Copyright (C) 1997-2006, International Business Machines
+* Copyright (C) 1997-2014, International Business Machines
* Corporation and others. All Rights Reserved.
******************************************************************************
* file name: nfrule.cpp
#if U_HAVE_RBNF
+#include "unicode/localpointer.h"
#include "unicode/rbnf.h"
#include "unicode/tblcoll.h"
#include "unicode/coleitr.h"
#include "nfrs.h"
#include "nfrlist.h"
#include "nfsubs.h"
-
-#include "util.h"
+#include "patternprops.h"
U_NAMESPACE_BEGIN
static const UChar gEqualPercent[] = {0x3D, 0x25, 0}; /* "=%" */
static const UChar gEqualHash[] = {0x3D, 0x23, 0}; /* "=#" */
static const UChar gEqualZero[] = {0x3D, 0x30, 0}; /* "=0" */
-static const UChar gEmptyString[] = {0}; /* "" */
static const UChar gGreaterGreaterGreater[] = {0x3E, 0x3E, 0x3E, 0}; /* ">>>" */
static const UChar * const tokenStrings[] = {
descriptor.setTo(description, 0, p);
++p;
- while (p < description.length() && uprv_isRuleWhiteSpace(description.charAt(p))) {
+ while (p < description.length() && PatternProps::isWhiteSpace(description.charAt(p))) {
++p;
}
description.removeBetween(0, p);
// check first to see if the rule descriptor matches the token
// for one of the special rules. If it does, set the base
// value to the correct identfier value
- if (descriptor == gMinusX) {
+ if (0 == descriptor.compare(gMinusX, 2)) {
setType(kNegativeNumberRule);
}
- else if (descriptor == gXDotX) {
+ else if (0 == descriptor.compare(gXDotX, 3)) {
setType(kImproperFractionRule);
}
- else if (descriptor == gZeroDotX) {
+ else if (0 == descriptor.compare(gZeroDotX, 3)) {
setType(kProperFractionRule);
}
- else if (descriptor == gXDotZero) {
+ else if (0 == descriptor.compare(gXDotZero, 3)) {
setType(kMasterRule);
}
else if (c == gSlash || c == gGreaterThan) {
break;
}
- else if (uprv_isRuleWhiteSpace(c) || c == gComma || c == gDot) {
+ else if (PatternProps::isWhiteSpace(c) || c == gComma || c == gDot) {
}
else {
// throw new IllegalArgumentException("Illegal character in rule descriptor");
else if (c == gGreaterThan) {
break;
}
- else if (uprv_isRuleWhiteSpace(c) || c == gComma || c == gDot) {
+ else if (PatternProps::isWhiteSpace(c) || c == gComma || c == gDot) {
}
else {
// throw new IllegalArgumentException("Illegal character is rule descriptor");
// at the end of the rule text
if (subStart == -1) {
return NFSubstitution::makeSubstitution(ruleText.length(), this, predecessor,
- ruleSet, rbnf, gEmptyString, status);
+ ruleSet, rbnf, UnicodeString(), status);
}
// special-case the ">>>" token, since searching for the > at the
// end will actually find the > in the middle
- if (ruleText.indexOf(gGreaterGreaterGreater) == subStart) {
+ if (ruleText.indexOf(gGreaterGreaterGreater, 3, 0) == subStart) {
subEnd = subStart + 2;
// otherwise the substitution token ends with the same character
// at the end of the rule
if (subEnd == -1) {
return NFSubstitution::makeSubstitution(ruleText.length(), this, predecessor,
- ruleSet, rbnf, gEmptyString, status);
+ ruleSet, rbnf, UnicodeString(), status);
}
// if we get here, we have a real substitution token (or at least
NFRule::_appendRuleText(UnicodeString& result) const
{
switch (getType()) {
- case kNegativeNumberRule: result.append(gMinusX); break;
- case kImproperFractionRule: result.append(gXDotX); break;
- case kProperFractionRule: result.append(gZeroDotX); break;
- case kMasterRule: result.append(gXDotZero); break;
+ case kNegativeNumberRule: result.append(gMinusX, 2); break;
+ case kImproperFractionRule: result.append(gXDotX, 3); break;
+ case kProperFractionRule: result.append(gZeroDotX, 3); break;
+ case kMasterRule: result.append(gXDotZero, 3); break;
default:
// for a normal rule, write out its base value, and if the radix is
// something other than 10, write out the radix (with the preceding
// if the rule text begins with a space, write an apostrophe
// (whitespace after the rule descriptor is ignored; the
// apostrophe is used to make the whitespace significant)
- if (ruleText.startsWith(gSpace) && sub1->getPos() != 0) {
+ if (ruleText.charAt(0) == gSpace && sub1->getPos() != 0) {
result.append(gTick);
}
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
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.
// isn't a RuleBasedCollator, because RuleBasedCollator defines
// the CollationElementIterator protocol. Hopefully, this
// will change someday.)
- RuleBasedCollator* collator = (RuleBasedCollator*)formatter->getCollator();
- CollationElementIterator* strIter = collator->createCollationElementIterator(str);
- CollationElementIterator* prefixIter = collator->createCollationElementIterator(prefix);
+ const RuleBasedCollator* collator = formatter->getCollator();
+ if (collator == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ LocalPointer<CollationElementIterator> strIter(collator->createCollationElementIterator(str));
+ LocalPointer<CollationElementIterator> prefixIter(collator->createCollationElementIterator(prefix));
+ // Check for memory allocation error.
+ if (strIter.isNull() || prefixIter.isNull()) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
UErrorCode err = U_ZERO_ERROR;
// if skipping over ignorables brought us to the end
// of the target string, we didn't match and return 0
if (oStr == CollationElementIterator::NULLORDER) {
- delete prefixIter;
- delete strIter;
return 0;
}
// get a mismatch, dump out and return 0
if (CollationElementIterator::primaryOrder(oStr)
!= CollationElementIterator::primaryOrder(oPrefix)) {
- delete prefixIter;
- delete strIter;
return 0;
// otherwise, advance to the next character in each string
#ifdef RBNF_DEBUG
fprintf(stderr, "prefix length: %d\n", result);
#endif
- delete prefixIter;
- delete strIter;
-
return result;
#if 0
//----------------------------------------------------------------
// 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) {
// a collation element iterator and make sure each collation
// element is 0 (ignorable) at the primary level
if (formatter->isLenient()) {
- RuleBasedCollator* collator = (RuleBasedCollator*)(formatter->getCollator());
- CollationElementIterator* iter = collator->createCollationElementIterator(str);
+ const RuleBasedCollator* collator = formatter->getCollator();
+ if (collator == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return FALSE;
+ }
+ LocalPointer<CollationElementIterator> iter(collator->createCollationElementIterator(str));
+
+ // Memory allocation error check.
+ if (iter.isNull()) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return FALSE;
+ }
UErrorCode err = U_ZERO_ERROR;
int32_t o = iter->next(err);
o = iter->next(err);
}
- delete iter;
return o == CollationElementIterator::NULLORDER;
}
#endif
/* U_HAVE_RBNF */
#endif
-
-