Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(158)

Side by Side Diff: source/i18n/nfrule.cpp

Issue 1621843002: ICU 56 update step 1 (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/icu.git@561
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « source/i18n/nfrule.h ('k') | source/i18n/nfsubs.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 ****************************************************************************** 2 ******************************************************************************
3 * Copyright (C) 1997-2014, International Business Machines 3 * Copyright (C) 1997-2015, International Business Machines
4 * Corporation and others. All Rights Reserved. 4 * Corporation and others. All Rights Reserved.
5 ****************************************************************************** 5 ******************************************************************************
6 * file name: nfrule.cpp 6 * file name: nfrule.cpp
7 * encoding: US-ASCII 7 * encoding: US-ASCII
8 * tab size: 8 (not used) 8 * tab size: 8 (not used)
9 * indentation:4 9 * indentation:4
10 * 10 *
11 * Modification history 11 * Modification history
12 * Date Name Comments 12 * Date Name Comments
13 * 10/11/2001 Doug Ported from ICU4J 13 * 10/11/2001 Doug Ported from ICU4J
(...skipping 10 matching lines...) Expand all
24 #include "unicode/upluralrules.h" 24 #include "unicode/upluralrules.h"
25 #include "unicode/coleitr.h" 25 #include "unicode/coleitr.h"
26 #include "unicode/uchar.h" 26 #include "unicode/uchar.h"
27 #include "nfrs.h" 27 #include "nfrs.h"
28 #include "nfrlist.h" 28 #include "nfrlist.h"
29 #include "nfsubs.h" 29 #include "nfsubs.h"
30 #include "patternprops.h" 30 #include "patternprops.h"
31 31
32 U_NAMESPACE_BEGIN 32 U_NAMESPACE_BEGIN
33 33
34 NFRule::NFRule(const RuleBasedNumberFormat* _rbnf) 34 NFRule::NFRule(const RuleBasedNumberFormat* _rbnf, const UnicodeString &_ruleTex t, UErrorCode &status)
35 : baseValue((int32_t)0) 35 : baseValue((int32_t)0)
36 , radix(0) 36 , radix(10)
37 , exponent(0) 37 , exponent(0)
38 , ruleText() 38 , decimalPoint(0)
39 , ruleText(_ruleText)
39 , sub1(NULL) 40 , sub1(NULL)
40 , sub2(NULL) 41 , sub2(NULL)
41 , formatter(_rbnf) 42 , formatter(_rbnf)
42 , rulePatternFormat(NULL) 43 , rulePatternFormat(NULL)
43 { 44 {
45 if (!ruleText.isEmpty()) {
46 parseRuleDescriptor(ruleText, status);
47 }
44 } 48 }
45 49
46 NFRule::~NFRule() 50 NFRule::~NFRule()
47 { 51 {
48 if (sub1 != sub2) { 52 if (sub1 != sub2) {
49 delete sub2; 53 delete sub2;
54 sub2 = NULL;
50 } 55 }
51 delete sub1; 56 delete sub1;
57 sub1 = NULL;
52 delete rulePatternFormat; 58 delete rulePatternFormat;
59 rulePatternFormat = NULL;
53 } 60 }
54 61
55 static const UChar gLeftBracket = 0x005b; 62 static const UChar gLeftBracket = 0x005b;
56 static const UChar gRightBracket = 0x005d; 63 static const UChar gRightBracket = 0x005d;
57 static const UChar gColon = 0x003a; 64 static const UChar gColon = 0x003a;
58 static const UChar gZero = 0x0030; 65 static const UChar gZero = 0x0030;
59 static const UChar gNine = 0x0039; 66 static const UChar gNine = 0x0039;
60 static const UChar gSpace = 0x0020; 67 static const UChar gSpace = 0x0020;
61 static const UChar gSlash = 0x002f; 68 static const UChar gSlash = 0x002f;
62 static const UChar gGreaterThan = 0x003e; 69 static const UChar gGreaterThan = 0x003e;
63 static const UChar gLessThan = 0x003c; 70 static const UChar gLessThan = 0x003c;
64 static const UChar gComma = 0x002c; 71 static const UChar gComma = 0x002c;
65 static const UChar gDot = 0x002e; 72 static const UChar gDot = 0x002e;
66 static const UChar gTick = 0x0027; 73 static const UChar gTick = 0x0027;
67 //static const UChar gMinus = 0x002d; 74 //static const UChar gMinus = 0x002d;
68 static const UChar gSemicolon = 0x003b; 75 static const UChar gSemicolon = 0x003b;
76 static const UChar gX = 0x0078;
69 77
70 static const UChar gMinusX[] = {0x2D, 0x78, 0}; /* "-x" */ 78 static const UChar gMinusX[] = {0x2D, 0x78, 0}; /* "-x" */
71 static const UChar gXDotX[] = {0x78, 0x2E, 0x78, 0}; /* "x.x" */ 79 static const UChar gInf[] = {0x49, 0x6E, 0x66, 0}; /* "Inf" */
72 static const UChar gXDotZero[] = {0x78, 0x2E, 0x30, 0}; /* "x.0" */ 80 static const UChar gNaN[] = {0x4E, 0x61, 0x4E, 0}; /* "NaN" */
73 static const UChar gZeroDotX[] = {0x30, 0x2E, 0x78, 0}; /* "0.x" */
74 81
75 static const UChar gDollarOpenParenthesis[] = {0x24, 0x28, 0}; /* "$(" */ 82 static const UChar gDollarOpenParenthesis[] = {0x24, 0x28, 0}; /* "$(" */
76 static const UChar gClosedParenthesisDollar[] = {0x29, 0x24, 0}; /* ")$" */ 83 static const UChar gClosedParenthesisDollar[] = {0x29, 0x24, 0}; /* ")$" */
77 84
78 static const UChar gLessLess[] = {0x3C, 0x3C, 0}; /* "<<" */ 85 static const UChar gLessLess[] = {0x3C, 0x3C, 0}; /* "<<" */
79 static const UChar gLessPercent[] = {0x3C, 0x25, 0}; /* "<%" */ 86 static const UChar gLessPercent[] = {0x3C, 0x25, 0}; /* "<%" */
80 static const UChar gLessHash[] = {0x3C, 0x23, 0}; /* "<#" */ 87 static const UChar gLessHash[] = {0x3C, 0x23, 0}; /* "<#" */
81 static const UChar gLessZero[] = {0x3C, 0x30, 0}; /* "<0" */ 88 static const UChar gLessZero[] = {0x3C, 0x30, 0}; /* "<0" */
82 static const UChar gGreaterGreater[] = {0x3E, 0x3E, 0}; /* ">>" */ 89 static const UChar gGreaterGreater[] = {0x3E, 0x3E, 0}; /* ">>" */
83 static const UChar gGreaterPercent[] = {0x3E, 0x25, 0}; /* ">%" */ 90 static const UChar gGreaterPercent[] = {0x3E, 0x25, 0}; /* ">%" */
84 static const UChar gGreaterHash[] = {0x3E, 0x23, 0}; /* ">#" */ 91 static const UChar gGreaterHash[] = {0x3E, 0x23, 0}; /* ">#" */
85 static const UChar gGreaterZero[] = {0x3E, 0x30, 0}; /* ">0" */ 92 static const UChar gGreaterZero[] = {0x3E, 0x30, 0}; /* ">0" */
86 static const UChar gEqualPercent[] = {0x3D, 0x25, 0}; /* "=%" */ 93 static const UChar gEqualPercent[] = {0x3D, 0x25, 0}; /* "=%" */
87 static const UChar gEqualHash[] = {0x3D, 0x23, 0}; /* "=#" */ 94 static const UChar gEqualHash[] = {0x3D, 0x23, 0}; /* "=#" */
88 static const UChar gEqualZero[] = {0x3D, 0x30, 0}; /* "=0" */ 95 static const UChar gEqualZero[] = {0x3D, 0x30, 0}; /* "=0" */
89 static const UChar gGreaterGreaterGreater[] = {0x3E, 0x3E, 0x3E, 0}; /* ">>>" */ 96 static const UChar gGreaterGreaterGreater[] = {0x3E, 0x3E, 0x3E, 0}; /* ">>>" */
90 97
91 static const UChar * const tokenStrings[] = { 98 static const UChar * const RULE_PREFIXES[] = {
92 gLessLess, gLessPercent, gLessHash, gLessZero, 99 gLessLess, gLessPercent, gLessHash, gLessZero,
93 gGreaterGreater, gGreaterPercent,gGreaterHash, gGreaterZero, 100 gGreaterGreater, gGreaterPercent,gGreaterHash, gGreaterZero,
94 gEqualPercent, gEqualHash, gEqualZero, NULL 101 gEqualPercent, gEqualHash, gEqualZero, NULL
95 }; 102 };
96 103
97 void 104 void
98 NFRule::makeRules(UnicodeString& description, 105 NFRule::makeRules(UnicodeString& description,
99 const NFRuleSet *ruleSet, 106 NFRuleSet *owner,
100 const NFRule *predecessor, 107 const NFRule *predecessor,
101 const RuleBasedNumberFormat *rbnf, 108 const RuleBasedNumberFormat *rbnf,
102 NFRuleList& rules, 109 NFRuleList& rules,
103 UErrorCode& status) 110 UErrorCode& status)
104 { 111 {
105 // we know we're making at least one rule, so go ahead and 112 // we know we're making at least one rule, so go ahead and
106 // new it up and initialize its basevalue and divisor 113 // new it up and initialize its basevalue and divisor
107 // (this also strips the rule descriptor, if any, off the 114 // (this also strips the rule descriptor, if any, off the
108 // descripton string) 115 // descripton string)
109 NFRule* rule1 = new NFRule(rbnf); 116 NFRule* rule1 = new NFRule(rbnf, description, status);
110 /* test for NULL */ 117 /* test for NULL */
111 if (rule1 == 0) { 118 if (rule1 == 0) {
112 status = U_MEMORY_ALLOCATION_ERROR; 119 status = U_MEMORY_ALLOCATION_ERROR;
113 return; 120 return;
114 } 121 }
115 rule1->parseRuleDescriptor(description, status); 122 description = rule1->ruleText;
116 123
117 // check the description to see whether there's text enclosed 124 // check the description to see whether there's text enclosed
118 // in brackets 125 // in brackets
119 int32_t brack1 = description.indexOf(gLeftBracket); 126 int32_t brack1 = description.indexOf(gLeftBracket);
120 int32_t brack2 = description.indexOf(gRightBracket); 127 int32_t brack2 = brack1 < 0 ? -1 : description.indexOf(gRightBracket);
121 128
122 // if the description doesn't contain a matched pair of brackets, 129 // if the description doesn't contain a matched pair of brackets,
123 // or if it's of a type that doesn't recognize bracketed text, 130 // or if it's of a type that doesn't recognize bracketed text,
124 // then leave the description alone, initialize the rule's 131 // then leave the description alone, initialize the rule's
125 // rule text and substitutions, and return that rule 132 // rule text and substitutions, and return that rule
126 if (brack1 == -1 || brack2 == -1 || brack1 > brack2 133 if (brack2 < 0 || brack1 > brack2
127 || rule1->getType() == kProperFractionRule 134 || rule1->getType() == kProperFractionRule
128 || rule1->getType() == kNegativeNumberRule) { 135 || rule1->getType() == kNegativeNumberRule
129 rule1->extractSubstitutions(ruleSet, description, predecessor, status); 136 || rule1->getType() == kInfinityRule
130 rules.add(rule1); 137 || rule1->getType() == kNaNRule)
131 } else { 138 {
139 rule1->extractSubstitutions(owner, description, predecessor, status);
140 }
141 else {
132 // if the description does contain a matched pair of brackets, 142 // if the description does contain a matched pair of brackets,
133 // then it's really shorthand for two rules (with one exception) 143 // then it's really shorthand for two rules (with one exception)
134 NFRule* rule2 = NULL; 144 NFRule* rule2 = NULL;
135 UnicodeString sbuf; 145 UnicodeString sbuf;
136 146
137 // we'll actually only split the rule into two rules if its 147 // we'll actually only split the rule into two rules if its
138 // base value is an even multiple of its divisor (or it's one 148 // base value is an even multiple of its divisor (or it's one
139 // of the special rules) 149 // of the special rules)
140 if ((rule1->baseValue > 0 150 if ((rule1->baseValue > 0
141 && (rule1->baseValue % util64_pow(rule1->radix, rule1->exponent)) == 0) 151 && (rule1->baseValue % util64_pow(rule1->radix, rule1->exponent)) == 0)
142 || rule1->getType() == kImproperFractionRule 152 || rule1->getType() == kImproperFractionRule
143 || rule1->getType() == kMasterRule) { 153 || rule1->getType() == kMasterRule) {
144 154
145 // if it passes that test, new up the second rule. If the 155 // if it passes that test, new up the second rule. If the
146 // rule set both rules will belong to is a fraction rule 156 // rule set both rules will belong to is a fraction rule
147 // set, they both have the same base value; otherwise, 157 // set, they both have the same base value; otherwise,
148 // increment the original rule's base value ("rule1" actually 158 // increment the original rule's base value ("rule1" actually
149 // goes SECOND in the rule set's rule list) 159 // goes SECOND in the rule set's rule list)
150 rule2 = new NFRule(rbnf); 160 rule2 = new NFRule(rbnf, UnicodeString(), status);
151 /* test for NULL */ 161 /* test for NULL */
152 if (rule2 == 0) { 162 if (rule2 == 0) {
153 status = U_MEMORY_ALLOCATION_ERROR; 163 status = U_MEMORY_ALLOCATION_ERROR;
154 return; 164 return;
155 } 165 }
156 if (rule1->baseValue >= 0) { 166 if (rule1->baseValue >= 0) {
157 rule2->baseValue = rule1->baseValue; 167 rule2->baseValue = rule1->baseValue;
158 if (!ruleSet->isFractionRuleSet()) { 168 if (!owner->isFractionRuleSet()) {
159 ++rule1->baseValue; 169 ++rule1->baseValue;
160 } 170 }
161 } 171 }
162 172
163 // if the description began with "x.x" and contains bracketed 173 // if the description began with "x.x" and contains bracketed
164 // text, it describes both the improper fraction rule and 174 // text, it describes both the improper fraction rule and
165 // the proper fraction rule 175 // the proper fraction rule
166 else if (rule1->getType() == kImproperFractionRule) { 176 else if (rule1->getType() == kImproperFractionRule) {
167 rule2->setType(kProperFractionRule); 177 rule2->setType(kProperFractionRule);
168 } 178 }
(...skipping 10 matching lines...) Expand all
179 // same divisor) 189 // same divisor)
180 rule2->radix = rule1->radix; 190 rule2->radix = rule1->radix;
181 rule2->exponent = rule1->exponent; 191 rule2->exponent = rule1->exponent;
182 192
183 // rule2's rule text omits the stuff in brackets: initalize 193 // rule2's rule text omits the stuff in brackets: initalize
184 // its rule text and substitutions accordingly 194 // its rule text and substitutions accordingly
185 sbuf.append(description, 0, brack1); 195 sbuf.append(description, 0, brack1);
186 if (brack2 + 1 < description.length()) { 196 if (brack2 + 1 < description.length()) {
187 sbuf.append(description, brack2 + 1, description.length() - brac k2 - 1); 197 sbuf.append(description, brack2 + 1, description.length() - brac k2 - 1);
188 } 198 }
189 rule2->extractSubstitutions(ruleSet, sbuf, predecessor, status); 199 rule2->extractSubstitutions(owner, sbuf, predecessor, status);
190 } 200 }
191 201
192 // rule1's text includes the text in the brackets but omits 202 // rule1's text includes the text in the brackets but omits
193 // the brackets themselves: initialize _its_ rule text and 203 // the brackets themselves: initialize _its_ rule text and
194 // substitutions accordingly 204 // substitutions accordingly
195 sbuf.setTo(description, 0, brack1); 205 sbuf.setTo(description, 0, brack1);
196 sbuf.append(description, brack1 + 1, brack2 - brack1 - 1); 206 sbuf.append(description, brack1 + 1, brack2 - brack1 - 1);
197 if (brack2 + 1 < description.length()) { 207 if (brack2 + 1 < description.length()) {
198 sbuf.append(description, brack2 + 1, description.length() - brack2 - 1); 208 sbuf.append(description, brack2 + 1, description.length() - brack2 - 1);
199 } 209 }
200 rule1->extractSubstitutions(ruleSet, sbuf, predecessor, status); 210 rule1->extractSubstitutions(owner, sbuf, predecessor, status);
201 211
202 // if we only have one rule, return it; if we have two, return 212 // if we only have one rule, return it; if we have two, return
203 // a two-element array containing them (notice that rule2 goes 213 // a two-element array containing them (notice that rule2 goes
204 // BEFORE rule1 in the list: in all cases, rule2 OMITS the 214 // BEFORE rule1 in the list: in all cases, rule2 OMITS the
205 // material in the brackets and rule1 INCLUDES the material 215 // material in the brackets and rule1 INCLUDES the material
206 // in the brackets) 216 // in the brackets)
207 if (rule2 != NULL) { 217 if (rule2 != NULL) {
208 rules.add(rule2); 218 if (rule2->baseValue >= kNoBase) {
219 rules.add(rule2);
220 }
221 else {
222 owner->setNonNumericalRule(rule2);
223 }
209 } 224 }
225 }
226 if (rule1->baseValue >= kNoBase) {
210 rules.add(rule1); 227 rules.add(rule1);
211 } 228 }
229 else {
230 owner->setNonNumericalRule(rule1);
231 }
212 } 232 }
213 233
214 /** 234 /**
215 * This function parses the rule's rule descriptor (i.e., the base 235 * This function parses the rule's rule descriptor (i.e., the base
216 * value and/or other tokens that precede the rule's rule text 236 * value and/or other tokens that precede the rule's rule text
217 * in the description) and sets the rule's base value, radix, and 237 * in the description) and sets the rule's base value, radix, and
218 * exponent according to the descriptor. (If the description doesn't 238 * exponent according to the descriptor. (If the description doesn't
219 * include a rule descriptor, then this function sets everything to 239 * include a rule descriptor, then this function sets everything to
220 * default values and the rule set sets the rule's real base value). 240 * default values and the rule set sets the rule's real base value).
221 * @param description The rule's description 241 * @param description The rule's description
222 * @return If "description" included a rule descriptor, this is 242 * @return If "description" included a rule descriptor, this is
223 * "description" with the descriptor and any trailing whitespace 243 * "description" with the descriptor and any trailing whitespace
224 * stripped off. Otherwise; it's "descriptor" unchangd. 244 * stripped off. Otherwise; it's "descriptor" unchangd.
225 */ 245 */
226 void 246 void
227 NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status) 247 NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status)
228 { 248 {
229 // the description consists of a rule descriptor and a rule body, 249 // the description consists of a rule descriptor and a rule body,
230 // separated by a colon. The rule descriptor is optional. If 250 // separated by a colon. The rule descriptor is optional. If
231 // it's omitted, just set the base value to 0. 251 // it's omitted, just set the base value to 0.
232 int32_t p = description.indexOf(gColon); 252 int32_t p = description.indexOf(gColon);
233 if (p == -1) { 253 if (p != -1) {
234 setBaseValue((int32_t)0, status);
235 } else {
236 // copy the descriptor out into its own string and strip it, 254 // copy the descriptor out into its own string and strip it,
237 // along with any trailing whitespace, out of the original 255 // along with any trailing whitespace, out of the original
238 // description 256 // description
239 UnicodeString descriptor; 257 UnicodeString descriptor;
240 descriptor.setTo(description, 0, p); 258 descriptor.setTo(description, 0, p);
241 259
242 ++p; 260 ++p;
243 while (p < description.length() && PatternProps::isWhiteSpace(descriptio n.charAt(p))) { 261 while (p < description.length() && PatternProps::isWhiteSpace(descriptio n.charAt(p))) {
244 ++p; 262 ++p;
245 } 263 }
246 description.removeBetween(0, p); 264 description.removeBetween(0, p);
247 265
248 // check first to see if the rule descriptor matches the token 266 // check first to see if the rule descriptor matches the token
249 // for one of the special rules. If it does, set the base 267 // for one of the special rules. If it does, set the base
250 // value to the correct identfier value 268 // value to the correct identifier value
251 if (0 == descriptor.compare(gMinusX, 2)) { 269 int descriptorLength = descriptor.length();
252 setType(kNegativeNumberRule); 270 UChar firstChar = descriptor.charAt(0);
253 } 271 UChar lastChar = descriptor.charAt(descriptorLength - 1);
254 else if (0 == descriptor.compare(gXDotX, 3)) { 272 if (firstChar >= gZero && firstChar <= gNine && lastChar != gX) {
255 setType(kImproperFractionRule); 273 // if the rule descriptor begins with a digit, it's a descriptor
256 } 274 // for a normal rule
257 else if (0 == descriptor.compare(gZeroDotX, 3)) { 275 // since we don't have Long.parseLong, and this isn't much work anyw ay,
258 setType(kProperFractionRule); 276 // just build up the value as we encounter the digits.
259 }
260 else if (0 == descriptor.compare(gXDotZero, 3)) {
261 setType(kMasterRule);
262 }
263
264 // if the rule descriptor begins with a digit, it's a descriptor
265 // for a normal rule
266 // since we don't have Long.parseLong, and this isn't much work anyway,
267 // just build up the value as we encounter the digits.
268 else if (descriptor.charAt(0) >= gZero && descriptor.charAt(0) <= gNine) {
269 int64_t val = 0; 277 int64_t val = 0;
270 p = 0; 278 p = 0;
271 UChar c = gSpace; 279 UChar c = gSpace;
272 280
273 // begin parsing the descriptor: copy digits 281 // begin parsing the descriptor: copy digits
274 // into "tempValue", skip periods, commas, and spaces, 282 // into "tempValue", skip periods, commas, and spaces,
275 // stop on a slash or > sign (or at the end of the string), 283 // stop on a slash or > sign (or at the end of the string),
276 // and throw an exception on any other character 284 // and throw an exception on any other character
277 int64_t ll_10 = 10; 285 int64_t ll_10 = 10;
278 while (p < descriptor.length()) { 286 while (p < descriptorLength) {
279 c = descriptor.charAt(p); 287 c = descriptor.charAt(p);
280 if (c >= gZero && c <= gNine) { 288 if (c >= gZero && c <= gNine) {
281 val = val * ll_10 + (int32_t)(c - gZero); 289 val = val * ll_10 + (int32_t)(c - gZero);
282 } 290 }
283 else if (c == gSlash || c == gGreaterThan) { 291 else if (c == gSlash || c == gGreaterThan) {
284 break; 292 break;
285 } 293 }
286 else if (PatternProps::isWhiteSpace(c) || c == gComma || c == gD ot) { 294 else if (PatternProps::isWhiteSpace(c) || c == gComma || c == gD ot) {
287 } 295 }
288 else { 296 else {
289 // throw new IllegalArgumentException("Illegal character in rule descriptor"); 297 // throw new IllegalArgumentException("Illegal character in rule descriptor");
290 status = U_PARSE_ERROR; 298 status = U_PARSE_ERROR;
291 return; 299 return;
292 } 300 }
293 ++p; 301 ++p;
294 } 302 }
295 303
296 // we have the base value, so set it 304 // we have the base value, so set it
297 setBaseValue(val, status); 305 setBaseValue(val, status);
298 306
299 // if we stopped the previous loop on a slash, we're 307 // if we stopped the previous loop on a slash, we're
300 // now parsing the rule's radix. Again, accumulate digits 308 // now parsing the rule's radix. Again, accumulate digits
301 // in tempValue, skip punctuation, stop on a > mark, and 309 // in tempValue, skip punctuation, stop on a > mark, and
302 // throw an exception on anything else 310 // throw an exception on anything else
303 if (c == gSlash) { 311 if (c == gSlash) {
304 val = 0; 312 val = 0;
305 ++p; 313 ++p;
306 int64_t ll_10 = 10; 314 int64_t ll_10 = 10;
307 while (p < descriptor.length()) { 315 while (p < descriptorLength) {
308 c = descriptor.charAt(p); 316 c = descriptor.charAt(p);
309 if (c >= gZero && c <= gNine) { 317 if (c >= gZero && c <= gNine) {
310 val = val * ll_10 + (int32_t)(c - gZero); 318 val = val * ll_10 + (int32_t)(c - gZero);
311 } 319 }
312 else if (c == gGreaterThan) { 320 else if (c == gGreaterThan) {
313 break; 321 break;
314 } 322 }
315 else if (PatternProps::isWhiteSpace(c) || c == gComma || c = = gDot) { 323 else if (PatternProps::isWhiteSpace(c) || c == gComma || c = = gDot) {
316 } 324 }
317 else { 325 else {
(...skipping 27 matching lines...) Expand all
345 --exponent; 353 --exponent;
346 } else { 354 } else {
347 // throw new IllegalArgumentException("Illegal character in rule descriptor"); 355 // throw new IllegalArgumentException("Illegal character in rule descriptor");
348 status = U_PARSE_ERROR; 356 status = U_PARSE_ERROR;
349 return; 357 return;
350 } 358 }
351 ++p; 359 ++p;
352 } 360 }
353 } 361 }
354 } 362 }
363 else if (0 == descriptor.compare(gMinusX, 2)) {
364 setType(kNegativeNumberRule);
365 }
366 else if (descriptorLength == 3) {
367 if (firstChar == gZero && lastChar == gX) {
368 setBaseValue(kProperFractionRule, status);
369 decimalPoint = descriptor.charAt(1);
370 }
371 else if (firstChar == gX && lastChar == gX) {
372 setBaseValue(kImproperFractionRule, status);
373 decimalPoint = descriptor.charAt(1);
374 }
375 else if (firstChar == gX && lastChar == gZero) {
376 setBaseValue(kMasterRule, status);
377 decimalPoint = descriptor.charAt(1);
378 }
379 else if (descriptor.compare(gNaN, 3) == 0) {
380 setBaseValue(kNaNRule, status);
381 }
382 else if (descriptor.compare(gInf, 3) == 0) {
383 setBaseValue(kInfinityRule, status);
384 }
385 }
355 } 386 }
387 // else use the default base value for now.
356 388
357 // finally, if the rule body begins with an apostrophe, strip it off 389 // finally, if the rule body begins with an apostrophe, strip it off
358 // (this is generally used to put whitespace at the beginning of 390 // (this is generally used to put whitespace at the beginning of
359 // a rule's rule text) 391 // a rule's rule text)
360 if (description.length() > 0 && description.charAt(0) == gTick) { 392 if (description.length() > 0 && description.charAt(0) == gTick) {
361 description.removeBetween(0, 1); 393 description.removeBetween(0, 1);
362 } 394 }
363 395
364 // return the description with all the stuff we've just waded through 396 // return the description with all the stuff we've just waded through
365 // stripped off the front. It now contains just the rule body. 397 // stripped off the front. It now contains just the rule body.
(...skipping 11 matching lines...) Expand all
377 void 409 void
378 NFRule::extractSubstitutions(const NFRuleSet* ruleSet, 410 NFRule::extractSubstitutions(const NFRuleSet* ruleSet,
379 const UnicodeString &ruleText, 411 const UnicodeString &ruleText,
380 const NFRule* predecessor, 412 const NFRule* predecessor,
381 UErrorCode& status) 413 UErrorCode& status)
382 { 414 {
383 if (U_FAILURE(status)) { 415 if (U_FAILURE(status)) {
384 return; 416 return;
385 } 417 }
386 this->ruleText = ruleText; 418 this->ruleText = ruleText;
387 this->rulePatternFormat = NULL;
388 sub1 = extractSubstitution(ruleSet, predecessor, status); 419 sub1 = extractSubstitution(ruleSet, predecessor, status);
389 if (sub1 == NULL || sub1->isNullSubstitution()) { 420 if (sub1 == NULL) {
390 // Small optimization. There is no need to create a redundant NullSubsti tution. 421 // Small optimization. There is no need to create a redundant NullSubsti tution.
391 sub2 = sub1; 422 sub2 = NULL;
392 } 423 }
393 else { 424 else {
394 sub2 = extractSubstitution(ruleSet, predecessor, status); 425 sub2 = extractSubstitution(ruleSet, predecessor, status);
395 } 426 }
396 int32_t pluralRuleStart = this->ruleText.indexOf(gDollarOpenParenthesis, -1, 0); 427 int32_t pluralRuleStart = this->ruleText.indexOf(gDollarOpenParenthesis, -1, 0);
397 int32_t pluralRuleEnd = (pluralRuleStart >= 0 ? this->ruleText.indexOf(gClos edParenthesisDollar, -1, pluralRuleStart) : -1); 428 int32_t pluralRuleEnd = (pluralRuleStart >= 0 ? this->ruleText.indexOf(gClos edParenthesisDollar, -1, pluralRuleStart) : -1);
398 if (pluralRuleEnd >= 0) { 429 if (pluralRuleEnd >= 0) {
399 int32_t endType = this->ruleText.indexOf(gComma, pluralRuleStart); 430 int32_t endType = this->ruleText.indexOf(gComma, pluralRuleStart);
400 if (endType < 0) { 431 if (endType < 0) {
401 status = U_PARSE_ERROR; 432 status = U_PARSE_ERROR;
(...skipping 30 matching lines...) Expand all
432 */ 463 */
433 NFSubstitution * 464 NFSubstitution *
434 NFRule::extractSubstitution(const NFRuleSet* ruleSet, 465 NFRule::extractSubstitution(const NFRuleSet* ruleSet,
435 const NFRule* predecessor, 466 const NFRule* predecessor,
436 UErrorCode& status) 467 UErrorCode& status)
437 { 468 {
438 NFSubstitution* result = NULL; 469 NFSubstitution* result = NULL;
439 470
440 // search the rule's rule text for the first two characters of 471 // search the rule's rule text for the first two characters of
441 // a substitution token 472 // a substitution token
442 int32_t subStart = indexOfAny(tokenStrings); 473 int32_t subStart = indexOfAnyRulePrefix();
443 int32_t subEnd = subStart; 474 int32_t subEnd = subStart;
444 475
445 // if we didn't find one, create a null substitution positioned 476 // if we didn't find one, create a null substitution positioned
446 // at the end of the rule text 477 // at the end of the rule text
447 if (subStart == -1) { 478 if (subStart == -1) {
448 return NFSubstitution::makeSubstitution(ruleText.length(), this, predece ssor, 479 return NULL;
449 ruleSet, this->formatter, UnicodeString(), status);
450 } 480 }
451 481
452 // special-case the ">>>" token, since searching for the > at the 482 // special-case the ">>>" token, since searching for the > at the
453 // end will actually find the > in the middle 483 // end will actually find the > in the middle
454 if (ruleText.indexOf(gGreaterGreaterGreater, 3, 0) == subStart) { 484 if (ruleText.indexOf(gGreaterGreaterGreater, 3, 0) == subStart) {
455 subEnd = subStart + 2; 485 subEnd = subStart + 2;
456 486
457 // otherwise the substitution token ends with the same character 487 // otherwise the substitution token ends with the same character
458 // it began with 488 // it began with
459 } else { 489 } else {
460 UChar c = ruleText.charAt(subStart); 490 UChar c = ruleText.charAt(subStart);
461 subEnd = ruleText.indexOf(c, subStart + 1); 491 subEnd = ruleText.indexOf(c, subStart + 1);
462 // special case for '<%foo<<' 492 // special case for '<%foo<<'
463 if (c == gLessThan && subEnd != -1 && subEnd < ruleText.length() - 1 && ruleText.charAt(subEnd+1) == c) { 493 if (c == gLessThan && subEnd != -1 && subEnd < ruleText.length() - 1 && ruleText.charAt(subEnd+1) == c) {
464 // ordinals use "=#,##0==%abbrev=" as their rule. Notice that the ' ==' in the middle 494 // ordinals use "=#,##0==%abbrev=" as their rule. Notice that the ' ==' in the middle
465 // occurs because of the juxtaposition of two different rules. The check for '<' is a hack 495 // occurs because of the juxtaposition of two different rules. The check for '<' is a hack
466 // to get around this. Having the duplicate at the front would caus e problems with 496 // to get around this. Having the duplicate at the front would caus e problems with
467 // rules like "<<%" to format, say, percents... 497 // rules like "<<%" to format, say, percents...
468 ++subEnd; 498 ++subEnd;
469 } 499 }
470 } 500 }
471 501
472 // if we don't find the end of the token (i.e., if we're on a single, 502 // if we don't find the end of the token (i.e., if we're on a single,
473 // unmatched token character), create a null substitution positioned 503 // unmatched token character), create a null substitution positioned
474 // at the end of the rule 504 // at the end of the rule
475 if (subEnd == -1) { 505 if (subEnd == -1) {
476 return NFSubstitution::makeSubstitution(ruleText.length(), this, predece ssor, 506 return NULL;
477 ruleSet, this->formatter, UnicodeString(), status);
478 } 507 }
479 508
480 // if we get here, we have a real substitution token (or at least 509 // if we get here, we have a real substitution token (or at least
481 // some text bounded by substitution token characters). Use 510 // some text bounded by substitution token characters). Use
482 // makeSubstitution() to create the right kind of substitution 511 // makeSubstitution() to create the right kind of substitution
483 UnicodeString subToken; 512 UnicodeString subToken;
484 subToken.setTo(ruleText, subStart, subEnd + 1 - subStart); 513 subToken.setTo(ruleText, subStart, subEnd + 1 - subStart);
485 result = NFSubstitution::makeSubstitution(subStart, this, predecessor, ruleS et, 514 result = NFSubstitution::makeSubstitution(subStart, this, predecessor, ruleS et,
486 this->formatter, subToken, status); 515 this->formatter, subToken, status);
487 516
488 // remove the substitution from the rule text 517 // remove the substitution from the rule text
489 ruleText.removeBetween(subStart, subEnd+1); 518 ruleText.removeBetween(subStart, subEnd+1);
490 519
491 return result; 520 return result;
492 } 521 }
493 522
494 /** 523 /**
495 * Sets the rule's base value, and causes the radix and exponent 524 * Sets the rule's base value, and causes the radix and exponent
496 * to be recalculated. This is used during construction when we 525 * to be recalculated. This is used during construction when we
497 * don't know the rule's base value until after it's been 526 * don't know the rule's base value until after it's been
498 * constructed. It should be used at any other time. 527 * constructed. It should be used at any other time.
499 * @param The new base value for the rule. 528 * @param The new base value for the rule.
500 */ 529 */
501 void 530 void
502 NFRule::setBaseValue(int64_t newBaseValue, UErrorCode& status) 531 NFRule::setBaseValue(int64_t newBaseValue, UErrorCode& status)
503 { 532 {
504 // set the base value 533 // set the base value
505 baseValue = newBaseValue; 534 baseValue = newBaseValue;
535 radix = 10;
506 536
507 // if this isn't a special rule, recalculate the radix and exponent 537 // if this isn't a special rule, recalculate the radix and exponent
508 // (the radix always defaults to 10; if it's supposed to be something 538 // (the radix always defaults to 10; if it's supposed to be something
509 // else, it's cleaned up by the caller and the exponent is 539 // else, it's cleaned up by the caller and the exponent is
510 // recalculated again-- the only function that does this is 540 // recalculated again-- the only function that does this is
511 // NFRule.parseRuleDescriptor() ) 541 // NFRule.parseRuleDescriptor() )
512 if (baseValue >= 1) { 542 if (baseValue >= 1) {
513 radix = 10;
514 exponent = expectedExponent(); 543 exponent = expectedExponent();
515 544
516 // this function gets called on a fully-constructed rule whose 545 // this function gets called on a fully-constructed rule whose
517 // description didn't specify a base value. This means it 546 // description didn't specify a base value. This means it
518 // has substitutions, and some substitutions hold on to copies 547 // has substitutions, and some substitutions hold on to copies
519 // of the rule's divisor. Fix their copies of the divisor. 548 // of the rule's divisor. Fix their copies of the divisor.
520 if (sub1 != NULL) { 549 if (sub1 != NULL) {
521 sub1->setDivisor(radix, exponent, status); 550 sub1->setDivisor(radix, exponent, status);
522 } 551 }
523 if (sub2 != NULL) { 552 if (sub2 != NULL) {
524 sub2->setDivisor(radix, exponent, status); 553 sub2->setDivisor(radix, exponent, status);
525 } 554 }
526 555
527 // if this is a special rule, its radix and exponent are basically 556 // if this is a special rule, its radix and exponent are basically
528 // ignored. Set them to "safe" default values 557 // ignored. Set them to "safe" default values
529 } else { 558 } else {
530 radix = 10;
531 exponent = 0; 559 exponent = 0;
532 } 560 }
533 } 561 }
534 562
535 /** 563 /**
536 * This calculates the rule's exponent based on its radix and base 564 * This calculates the rule's exponent based on its radix and base
537 * value. This will be the highest power the radix can be raised to 565 * value. This will be the highest power the radix can be raised to
538 * and still produce a result less than or equal to the base value. 566 * and still produce a result less than or equal to the base value.
539 */ 567 */
540 int16_t 568 int16_t
(...skipping 12 matching lines...) Expand all
553 int16_t tempResult = (int16_t)(uprv_log((double)baseValue) / uprv_log((doubl e)radix)); 581 int16_t tempResult = (int16_t)(uprv_log((double)baseValue) / uprv_log((doubl e)radix));
554 int64_t temp = util64_pow(radix, tempResult + 1); 582 int64_t temp = util64_pow(radix, tempResult + 1);
555 if (temp <= baseValue) { 583 if (temp <= baseValue) {
556 tempResult += 1; 584 tempResult += 1;
557 } 585 }
558 return tempResult; 586 return tempResult;
559 } 587 }
560 588
561 /** 589 /**
562 * Searches the rule's rule text for any of the specified strings. 590 * Searches the rule's rule text for any of the specified strings.
563 * @param strings An array of strings to search the rule's rule
564 * text for
565 * @return The index of the first match in the rule's rule text 591 * @return The index of the first match in the rule's rule text
566 * (i.e., the first substring in the rule's rule text that matches 592 * (i.e., the first substring in the rule's rule text that matches
567 * _any_ of the strings in "strings"). If none of the strings in 593 * _any_ of the strings in "strings"). If none of the strings in
568 * "strings" is found in the rule's rule text, returns -1. 594 * "strings" is found in the rule's rule text, returns -1.
569 */ 595 */
570 int32_t 596 int32_t
571 NFRule::indexOfAny(const UChar* const strings[]) const 597 NFRule::indexOfAnyRulePrefix() const
572 { 598 {
573 int result = -1; 599 int result = -1;
574 for (int i = 0; strings[i]; i++) { 600 for (int i = 0; RULE_PREFIXES[i]; i++) {
575 int32_t pos = ruleText.indexOf(*strings[i]); 601 int32_t pos = ruleText.indexOf(*RULE_PREFIXES[i]);
576 if (pos != -1 && (result == -1 || pos < result)) { 602 if (pos != -1 && (result == -1 || pos < result)) {
577 result = pos; 603 result = pos;
578 } 604 }
579 } 605 }
580 return result; 606 return result;
581 } 607 }
582 608
583 //----------------------------------------------------------------------- 609 //-----------------------------------------------------------------------
584 // boilerplate 610 // boilerplate
585 //----------------------------------------------------------------------- 611 //-----------------------------------------------------------------------
586 612
613 static UBool
614 util_equalSubstitutions(const NFSubstitution* sub1, const NFSubstitution* sub2)
615 {
616 if (sub1) {
617 if (sub2) {
618 return *sub1 == *sub2;
619 }
620 } else if (!sub2) {
621 return TRUE;
622 }
623 return FALSE;
624 }
625
587 /** 626 /**
588 * Tests two rules for equality. 627 * Tests two rules for equality.
589 * @param that The rule to compare this one against 628 * @param that The rule to compare this one against
590 * @return True is the two rules are functionally equivalent 629 * @return True is the two rules are functionally equivalent
591 */ 630 */
592 UBool 631 UBool
593 NFRule::operator==(const NFRule& rhs) const 632 NFRule::operator==(const NFRule& rhs) const
594 { 633 {
595 return baseValue == rhs.baseValue 634 return baseValue == rhs.baseValue
596 && radix == rhs.radix 635 && radix == rhs.radix
597 && exponent == rhs.exponent 636 && exponent == rhs.exponent
598 && ruleText == rhs.ruleText 637 && ruleText == rhs.ruleText
599 && *sub1 == *rhs.sub1 638 && util_equalSubstitutions(sub1, rhs.sub1)
600 && *sub2 == *rhs.sub2; 639 && util_equalSubstitutions(sub2, rhs.sub2);
601 } 640 }
602 641
603 /** 642 /**
604 * Returns a textual representation of the rule. This won't 643 * Returns a textual representation of the rule. This won't
605 * necessarily be the same as the description that this rule 644 * necessarily be the same as the description that this rule
606 * was created with, but it will produce the same result. 645 * was created with, but it will produce the same result.
607 * @return A textual description of the rule 646 * @return A textual description of the rule
608 */ 647 */
609 static void util_append64(UnicodeString& result, int64_t n) 648 static void util_append64(UnicodeString& result, int64_t n)
610 { 649 {
611 UChar buffer[256]; 650 UChar buffer[256];
612 int32_t len = util64_tou(n, buffer, sizeof(buffer)); 651 int32_t len = util64_tou(n, buffer, sizeof(buffer));
613 UnicodeString temp(buffer, len); 652 UnicodeString temp(buffer, len);
614 result.append(temp); 653 result.append(temp);
615 } 654 }
616 655
617 void 656 void
618 NFRule::_appendRuleText(UnicodeString& result) const 657 NFRule::_appendRuleText(UnicodeString& result) const
619 { 658 {
620 switch (getType()) { 659 switch (getType()) {
621 case kNegativeNumberRule: result.append(gMinusX, 2); break; 660 case kNegativeNumberRule: result.append(gMinusX, 2); break;
622 case kImproperFractionRule: result.append(gXDotX, 3); break; 661 case kImproperFractionRule: result.append(gX).append(decimalPoint == 0 ? gDo t : decimalPoint).append(gX); break;
623 case kProperFractionRule: result.append(gZeroDotX, 3); break; 662 case kProperFractionRule: result.append(gZero).append(decimalPoint == 0 ? gD ot : decimalPoint).append(gX); break;
624 case kMasterRule: result.append(gXDotZero, 3); break; 663 case kMasterRule: result.append(gX).append(decimalPoint == 0 ? gDot : decima lPoint).append(gZero); break;
664 case kInfinityRule: result.append(gInf, 3); break;
665 case kNaNRule: result.append(gNaN, 3); break;
625 default: 666 default:
626 // for a normal rule, write out its base value, and if the radix is 667 // for a normal rule, write out its base value, and if the radix is
627 // something other than 10, write out the radix (with the preceding 668 // something other than 10, write out the radix (with the preceding
628 // slash, of course). Then calculate the expected exponent and if 669 // slash, of course). Then calculate the expected exponent and if
629 // if isn't the same as the actual exponent, write an appropriate 670 // if isn't the same as the actual exponent, write an appropriate
630 // number of > signs. Finally, terminate the whole thing with 671 // number of > signs. Finally, terminate the whole thing with
631 // a colon. 672 // a colon.
632 util_append64(result, baseValue); 673 util_append64(result, baseValue);
633 if (radix != 10) { 674 if (radix != 10) {
634 result.append(gSlash); 675 result.append(gSlash);
635 util_append64(result, radix); 676 util_append64(result, radix);
636 } 677 }
637 int numCarets = expectedExponent() - exponent; 678 int numCarets = expectedExponent() - exponent;
638 for (int i = 0; i < numCarets; i++) { 679 for (int i = 0; i < numCarets; i++) {
639 result.append(gGreaterThan); 680 result.append(gGreaterThan);
640 } 681 }
641 break; 682 break;
642 } 683 }
643 result.append(gColon); 684 result.append(gColon);
644 result.append(gSpace); 685 result.append(gSpace);
645 686
646 // if the rule text begins with a space, write an apostrophe 687 // if the rule text begins with a space, write an apostrophe
647 // (whitespace after the rule descriptor is ignored; the 688 // (whitespace after the rule descriptor is ignored; the
648 // apostrophe is used to make the whitespace significant) 689 // apostrophe is used to make the whitespace significant)
649 if (ruleText.charAt(0) == gSpace && sub1->getPos() != 0) { 690 if (ruleText.charAt(0) == gSpace && (sub1 == NULL || sub1->getPos() != 0)) {
650 result.append(gTick); 691 result.append(gTick);
651 } 692 }
652 693
653 // now, write the rule's rule text, inserting appropriate 694 // now, write the rule's rule text, inserting appropriate
654 // substitution tokens in the appropriate places 695 // substitution tokens in the appropriate places
655 UnicodeString ruleTextCopy; 696 UnicodeString ruleTextCopy;
656 ruleTextCopy.setTo(ruleText); 697 ruleTextCopy.setTo(ruleText);
657 698
658 UnicodeString temp; 699 UnicodeString temp;
659 sub2->toString(temp); 700 if (sub2 != NULL) {
660 ruleTextCopy.insert(sub2->getPos(), temp); 701 sub2->toString(temp);
661 sub1->toString(temp); 702 ruleTextCopy.insert(sub2->getPos(), temp);
662 ruleTextCopy.insert(sub1->getPos(), temp); 703 }
704 if (sub1 != NULL) {
705 sub1->toString(temp);
706 ruleTextCopy.insert(sub1->getPos(), temp);
707 }
663 708
664 result.append(ruleTextCopy); 709 result.append(ruleTextCopy);
665 710
666 // and finally, top the whole thing off with a semicolon and 711 // and finally, top the whole thing off with a semicolon and
667 // return the result 712 // return the result
668 result.append(gSemicolon); 713 result.append(gSemicolon);
669 } 714 }
670 715
671 //----------------------------------------------------------------------- 716 //-----------------------------------------------------------------------
672 // formatting 717 // formatting
673 //----------------------------------------------------------------------- 718 //-----------------------------------------------------------------------
674 719
675 /** 720 /**
676 * Formats the number, and inserts the resulting text into 721 * Formats the number, and inserts the resulting text into
677 * toInsertInto. 722 * toInsertInto.
678 * @param number The number being formatted 723 * @param number The number being formatted
679 * @param toInsertInto The string where the resultant text should 724 * @param toInsertInto The string where the resultant text should
680 * be inserted 725 * be inserted
681 * @param pos The position in toInsertInto where the resultant text 726 * @param pos The position in toInsertInto where the resultant text
682 * should be inserted 727 * should be inserted
683 */ 728 */
684 void 729 void
685 NFRule::doFormat(int64_t number, UnicodeString& toInsertInto, int32_t pos, UErro rCode& status) const 730 NFRule::doFormat(int64_t number, UnicodeString& toInsertInto, int32_t pos, int32 _t recursionCount, UErrorCode& status) const
686 { 731 {
687 // first, insert the rule's rule text into toInsertInto at the 732 // first, insert the rule's rule text into toInsertInto at the
688 // specified position, then insert the results of the substitutions 733 // specified position, then insert the results of the substitutions
689 // into the right places in toInsertInto (notice we do the 734 // into the right places in toInsertInto (notice we do the
690 // substitutions in reverse order so that the offsets don't get 735 // substitutions in reverse order so that the offsets don't get
691 // messed up) 736 // messed up)
692 int32_t pluralRuleStart = ruleText.length(); 737 int32_t pluralRuleStart = ruleText.length();
693 int32_t lengthOffset = 0; 738 int32_t lengthOffset = 0;
694 if (!rulePatternFormat) { 739 if (!rulePatternFormat) {
695 toInsertInto.insert(pos, ruleText); 740 toInsertInto.insert(pos, ruleText);
696 } 741 }
697 else { 742 else {
698 pluralRuleStart = ruleText.indexOf(gDollarOpenParenthesis, -1, 0); 743 pluralRuleStart = ruleText.indexOf(gDollarOpenParenthesis, -1, 0);
699 int pluralRuleEnd = ruleText.indexOf(gClosedParenthesisDollar, -1, plura lRuleStart); 744 int pluralRuleEnd = ruleText.indexOf(gClosedParenthesisDollar, -1, plura lRuleStart);
700 int initialLength = toInsertInto.length(); 745 int initialLength = toInsertInto.length();
701 if (pluralRuleEnd < ruleText.length() - 1) { 746 if (pluralRuleEnd < ruleText.length() - 1) {
702 toInsertInto.insert(pos, ruleText.tempSubString(pluralRuleEnd + 2)); 747 toInsertInto.insert(pos, ruleText.tempSubString(pluralRuleEnd + 2));
703 } 748 }
704 toInsertInto.insert(pos, 749 toInsertInto.insert(pos,
705 rulePatternFormat->format((int32_t)(number/uprv_pow(radix, exponent) ), status)); 750 rulePatternFormat->format((int32_t)(number/uprv_pow(radix, exponent) ), status));
706 if (pluralRuleStart > 0) { 751 if (pluralRuleStart > 0) {
707 toInsertInto.insert(pos, ruleText.tempSubString(0, pluralRuleStart)) ; 752 toInsertInto.insert(pos, ruleText.tempSubString(0, pluralRuleStart)) ;
708 } 753 }
709 lengthOffset = ruleText.length() - (toInsertInto.length() - initialLengt h); 754 lengthOffset = ruleText.length() - (toInsertInto.length() - initialLengt h);
710 } 755 }
711 756
712 if (!sub2->isNullSubstitution()) { 757 if (sub2 != NULL) {
713 sub2->doSubstitution(number, toInsertInto, pos - (sub2->getPos() > plura lRuleStart ? lengthOffset : 0), status); 758 sub2->doSubstitution(number, toInsertInto, pos - (sub2->getPos() > plura lRuleStart ? lengthOffset : 0), recursionCount, status);
714 } 759 }
715 if (!sub1->isNullSubstitution()) { 760 if (sub1 != NULL) {
716 sub1->doSubstitution(number, toInsertInto, pos - (sub1->getPos() > plura lRuleStart ? lengthOffset : 0), status); 761 sub1->doSubstitution(number, toInsertInto, pos - (sub1->getPos() > plura lRuleStart ? lengthOffset : 0), recursionCount, status);
717 } 762 }
718 } 763 }
719 764
720 /** 765 /**
721 * Formats the number, and inserts the resulting text into 766 * Formats the number, and inserts the resulting text into
722 * toInsertInto. 767 * toInsertInto.
723 * @param number The number being formatted 768 * @param number The number being formatted
724 * @param toInsertInto The string where the resultant text should 769 * @param toInsertInto The string where the resultant text should
725 * be inserted 770 * be inserted
726 * @param pos The position in toInsertInto where the resultant text 771 * @param pos The position in toInsertInto where the resultant text
727 * should be inserted 772 * should be inserted
728 */ 773 */
729 void 774 void
730 NFRule::doFormat(double number, UnicodeString& toInsertInto, int32_t pos, UError Code& status) const 775 NFRule::doFormat(double number, UnicodeString& toInsertInto, int32_t pos, int32_ t recursionCount, UErrorCode& status) const
731 { 776 {
732 // first, insert the rule's rule text into toInsertInto at the 777 // first, insert the rule's rule text into toInsertInto at the
733 // specified position, then insert the results of the substitutions 778 // specified position, then insert the results of the substitutions
734 // into the right places in toInsertInto 779 // into the right places in toInsertInto
735 // [again, we have two copies of this routine that do the same thing 780 // [again, we have two copies of this routine that do the same thing
736 // so that we don't sacrifice precision in a long by casting it 781 // so that we don't sacrifice precision in a long by casting it
737 // to a double] 782 // to a double]
738 int32_t pluralRuleStart = ruleText.length(); 783 int32_t pluralRuleStart = ruleText.length();
739 int32_t lengthOffset = 0; 784 int32_t lengthOffset = 0;
740 if (!rulePatternFormat) { 785 if (!rulePatternFormat) {
741 toInsertInto.insert(pos, ruleText); 786 toInsertInto.insert(pos, ruleText);
742 } 787 }
743 else { 788 else {
744 pluralRuleStart = ruleText.indexOf(gDollarOpenParenthesis, -1, 0); 789 pluralRuleStart = ruleText.indexOf(gDollarOpenParenthesis, -1, 0);
745 int pluralRuleEnd = ruleText.indexOf(gClosedParenthesisDollar, -1, plura lRuleStart); 790 int pluralRuleEnd = ruleText.indexOf(gClosedParenthesisDollar, -1, plura lRuleStart);
746 int initialLength = toInsertInto.length(); 791 int initialLength = toInsertInto.length();
747 if (pluralRuleEnd < ruleText.length() - 1) { 792 if (pluralRuleEnd < ruleText.length() - 1) {
748 toInsertInto.insert(pos, ruleText.tempSubString(pluralRuleEnd + 2)); 793 toInsertInto.insert(pos, ruleText.tempSubString(pluralRuleEnd + 2));
749 } 794 }
750 toInsertInto.insert(pos, 795 double pluralVal = number;
751 rulePatternFormat->format((int32_t)(number/uprv_pow(radix, exponent) ), status)); 796 if (0 <= pluralVal && pluralVal < 1) {
797 // We're in a fractional rule, and we have to match the NumeratorSub stitution behavior.
798 // 2.3 can become 0.2999999999999998 for the fraction due to roundin g errors.
799 pluralVal = uprv_round(pluralVal * uprv_pow(radix, exponent));
800 }
801 else {
802 pluralVal = pluralVal / uprv_pow(radix, exponent);
803 }
804 toInsertInto.insert(pos, rulePatternFormat->format((int32_t)(pluralVal), status));
752 if (pluralRuleStart > 0) { 805 if (pluralRuleStart > 0) {
753 toInsertInto.insert(pos, ruleText.tempSubString(0, pluralRuleStart)) ; 806 toInsertInto.insert(pos, ruleText.tempSubString(0, pluralRuleStart)) ;
754 } 807 }
755 lengthOffset = ruleText.length() - (toInsertInto.length() - initialLengt h); 808 lengthOffset = ruleText.length() - (toInsertInto.length() - initialLengt h);
756 } 809 }
757 810
758 if (!sub2->isNullSubstitution()) { 811 if (sub2 != NULL) {
759 sub2->doSubstitution(number, toInsertInto, pos - (sub2->getPos() > plura lRuleStart ? lengthOffset : 0), status); 812 sub2->doSubstitution(number, toInsertInto, pos - (sub2->getPos() > plura lRuleStart ? lengthOffset : 0), recursionCount, status);
760 } 813 }
761 if (!sub1->isNullSubstitution()) { 814 if (sub1 != NULL) {
762 sub1->doSubstitution(number, toInsertInto, pos - (sub1->getPos() > plura lRuleStart ? lengthOffset : 0), status); 815 sub1->doSubstitution(number, toInsertInto, pos - (sub1->getPos() > plura lRuleStart ? lengthOffset : 0), recursionCount, status);
763 } 816 }
764 } 817 }
765 818
766 /** 819 /**
767 * Used by the owning rule set to determine whether to invoke the 820 * Used by the owning rule set to determine whether to invoke the
768 * rollback rule (i.e., whether this rule or the one that precedes 821 * rollback rule (i.e., whether this rule or the one that precedes
769 * it in the rule set's list should be used to format the number) 822 * it in the rule set's list should be used to format the number)
770 * @param The number being formatted 823 * @param The number being formatted
771 * @return True if the rule set should use the rule that precedes 824 * @return True if the rule set should use the rule that precedes
772 * this one in its list; false if it should use this rule 825 * this one in its list; false if it should use this rule
(...skipping 10 matching lines...) Expand all
783 // that expands into 836 // that expands into
784 // 100: << hundred; 837 // 100: << hundred;
785 // 101: << hundred >>; 838 // 101: << hundred >>;
786 // internally. But when we're formatting 200, if we use the rule 839 // internally. But when we're formatting 200, if we use the rule
787 // at 101, which would normally apply, we get "two hundred zero". 840 // at 101, which would normally apply, we get "two hundred zero".
788 // To prevent this, we roll back and use the rule at 100 instead. 841 // To prevent this, we roll back and use the rule at 100 instead.
789 // This is the logic that makes this happen: the rule at 101 has 842 // This is the logic that makes this happen: the rule at 101 has
790 // a modulus substitution, its base value isn't an even multiple 843 // a modulus substitution, its base value isn't an even multiple
791 // of 100, and the value we're trying to format _is_ an even 844 // of 100, and the value we're trying to format _is_ an even
792 // multiple of 100. This is called the "rollback rule." 845 // multiple of 100. This is called the "rollback rule."
793 if ((sub1->isModulusSubstitution()) || (sub2->isModulusSubstitution())) { 846 if ((sub1 != NULL && sub1->isModulusSubstitution()) || (sub2 != NULL && sub2 ->isModulusSubstitution())) {
794 int64_t re = util64_pow(radix, exponent); 847 int64_t re = util64_pow(radix, exponent);
795 return uprv_fmod(number, (double)re) == 0 && (baseValue % re) != 0; 848 return uprv_fmod(number, (double)re) == 0 && (baseValue % re) != 0;
796 } 849 }
797 return FALSE; 850 return FALSE;
798 } 851 }
799 852
800 //----------------------------------------------------------------------- 853 //-----------------------------------------------------------------------
801 // parsing 854 // parsing
802 //----------------------------------------------------------------------- 855 //-----------------------------------------------------------------------
803 856
(...skipping 22 matching lines...) Expand all
826 int len = us.length(); 879 int len = us.length();
827 char* buf = (char *)uprv_malloc((len+1)*sizeof(char)); //new char[len+1]; 880 char* buf = (char *)uprv_malloc((len+1)*sizeof(char)); //new char[len+1];
828 if (buf != NULL) { 881 if (buf != NULL) {
829 us.extract(0, len, buf); 882 us.extract(0, len, buf);
830 buf[len] = 0; 883 buf[len] = 0;
831 fprintf(f, "%s", buf); 884 fprintf(f, "%s", buf);
832 uprv_free(buf); //delete[] buf; 885 uprv_free(buf); //delete[] buf;
833 } 886 }
834 } 887 }
835 #endif 888 #endif
836
837 UBool 889 UBool
838 NFRule::doParse(const UnicodeString& text, 890 NFRule::doParse(const UnicodeString& text,
839 ParsePosition& parsePosition, 891 ParsePosition& parsePosition,
840 UBool isFractionRule, 892 UBool isFractionRule,
841 double upperBound, 893 double upperBound,
842 Formattable& resVal) const 894 Formattable& resVal) const
843 { 895 {
844 // internally we operate on a copy of the string being parsed 896 // internally we operate on a copy of the string being parsed
845 // (because we're going to change it) and use our own ParsePosition 897 // (because we're going to change it) and use our own ParsePosition
846 ParsePosition pp; 898 ParsePosition pp;
847 UnicodeString workText(text); 899 UnicodeString workText(text);
848 900
901 int32_t sub1Pos = sub1 != NULL ? sub1->getPos() : ruleText.length();
902 int32_t sub2Pos = sub2 != NULL ? sub2->getPos() : ruleText.length();
903
849 // check to see whether the text before the first substitution 904 // check to see whether the text before the first substitution
850 // matches the text at the beginning of the string being 905 // matches the text at the beginning of the string being
851 // parsed. If it does, strip that off the front of workText; 906 // parsed. If it does, strip that off the front of workText;
852 // otherwise, dump out with a mismatch 907 // otherwise, dump out with a mismatch
853 UnicodeString prefix; 908 UnicodeString prefix;
854 prefix.setTo(ruleText, 0, sub1->getPos()); 909 prefix.setTo(ruleText, 0, sub1Pos);
855 910
856 #ifdef RBNF_DEBUG 911 #ifdef RBNF_DEBUG
857 fprintf(stderr, "doParse %x ", this); 912 fprintf(stderr, "doParse %p ", this);
858 { 913 {
859 UnicodeString rt; 914 UnicodeString rt;
860 _appendRuleText(rt); 915 _appendRuleText(rt);
861 dumpUS(stderr, rt); 916 dumpUS(stderr, rt);
862 } 917 }
863 918
864 fprintf(stderr, " text: '", this); 919 fprintf(stderr, " text: '");
865 dumpUS(stderr, text); 920 dumpUS(stderr, text);
866 fprintf(stderr, "' prefix: '"); 921 fprintf(stderr, "' prefix: '");
867 dumpUS(stderr, prefix); 922 dumpUS(stderr, prefix);
868 #endif 923 #endif
869 stripPrefix(workText, prefix, pp); 924 stripPrefix(workText, prefix, pp);
870 int32_t prefixLength = text.length() - workText.length(); 925 int32_t prefixLength = text.length() - workText.length();
871 926
872 #ifdef RBNF_DEBUG 927 #ifdef RBNF_DEBUG
873 fprintf(stderr, "' pl: %d ppi: %d s1p: %d\n", prefixLength, pp.getIndex(), s ub1->getPos()); 928 fprintf(stderr, "' pl: %d ppi: %d s1p: %d\n", prefixLength, pp.getIndex(), s ub1Pos);
874 #endif 929 #endif
875 930
876 if (pp.getIndex() == 0 && sub1->getPos() != 0) { 931 if (pp.getIndex() == 0 && sub1Pos != 0) {
877 // commented out because ParsePosition doesn't have error index in 1.1.x 932 // commented out because ParsePosition doesn't have error index in 1.1.x
878 // restored for ICU4C port 933 // restored for ICU4C port
879 parsePosition.setErrorIndex(pp.getErrorIndex()); 934 parsePosition.setErrorIndex(pp.getErrorIndex());
880 resVal.setLong(0); 935 resVal.setLong(0);
881 return TRUE; 936 return TRUE;
882 } 937 }
938 if (baseValue == kInfinityRule) {
939 // If you match this, don't try to perform any calculations on it.
940 parsePosition.setIndex(pp.getIndex());
941 resVal.setDouble(uprv_getInfinity());
942 return TRUE;
943 }
944 if (baseValue == kNaNRule) {
945 // If you match this, don't try to perform any calculations on it.
946 parsePosition.setIndex(pp.getIndex());
947 resVal.setDouble(uprv_getNaN());
948 return TRUE;
949 }
883 950
884 // this is the fun part. The basic guts of the rule-matching 951 // this is the fun part. The basic guts of the rule-matching
885 // logic is matchToDelimiter(), which is called twice. The first 952 // logic is matchToDelimiter(), which is called twice. The first
886 // time it searches the input string for the rule text BETWEEN 953 // time it searches the input string for the rule text BETWEEN
887 // the substitutions and tries to match the intervening text 954 // the substitutions and tries to match the intervening text
888 // in the input string with the first substitution. If that 955 // in the input string with the first substitution. If that
889 // succeeds, it then calls it again, this time to look for the 956 // succeeds, it then calls it again, this time to look for the
890 // rule text after the second substitution and to match the 957 // rule text after the second substitution and to match the
891 // intervening input text against the second substitution. 958 // intervening input text against the second substitution.
892 // 959 //
(...skipping 23 matching lines...) Expand all
916 double tempBaseValue = (double)(baseValue <= 0 ? 0 : baseValue); 983 double tempBaseValue = (double)(baseValue <= 0 ? 0 : baseValue);
917 984
918 UnicodeString temp; 985 UnicodeString temp;
919 do { 986 do {
920 // our partial parse result starts out as this rule's base 987 // our partial parse result starts out as this rule's base
921 // value. If it finds a successful match, matchToDelimiter() 988 // value. If it finds a successful match, matchToDelimiter()
922 // will compose this in some way with what it gets back from 989 // will compose this in some way with what it gets back from
923 // the substitution, giving us a new partial parse result 990 // the substitution, giving us a new partial parse result
924 pp.setIndex(0); 991 pp.setIndex(0);
925 992
926 temp.setTo(ruleText, sub1->getPos(), sub2->getPos() - sub1->getPos()); 993 temp.setTo(ruleText, sub1Pos, sub2Pos - sub1Pos);
927 double partialResult = matchToDelimiter(workText, start, tempBaseValue, 994 double partialResult = matchToDelimiter(workText, start, tempBaseValue,
928 temp, pp, sub1, 995 temp, pp, sub1,
929 upperBound); 996 upperBound);
930 997
931 // if we got a successful match (or were trying to match a 998 // if we got a successful match (or were trying to match a
932 // null substitution), pp is now pointing at the first unmatched 999 // null substitution), pp is now pointing at the first unmatched
933 // character. Take note of that, and try matchToDelimiter() 1000 // character. Take note of that, and try matchToDelimiter()
934 // on the input text again 1001 // on the input text again
935 if (pp.getIndex() != 0 || sub1->isNullSubstitution()) { 1002 if (pp.getIndex() != 0 || sub1 == NULL) {
936 start = pp.getIndex(); 1003 start = pp.getIndex();
937 1004
938 UnicodeString workText2; 1005 UnicodeString workText2;
939 workText2.setTo(workText, pp.getIndex(), workText.length() - pp.getI ndex()); 1006 workText2.setTo(workText, pp.getIndex(), workText.length() - pp.getI ndex());
940 ParsePosition pp2; 1007 ParsePosition pp2;
941 1008
942 // the second matchToDelimiter() will compose our previous 1009 // the second matchToDelimiter() will compose our previous
943 // partial result with whatever it gets back from its 1010 // partial result with whatever it gets back from its
944 // substitution if there's a successful match, giving us 1011 // substitution if there's a successful match, giving us
945 // a real result 1012 // a real result
946 temp.setTo(ruleText, sub2->getPos(), ruleText.length() - sub2->getPo s()); 1013 temp.setTo(ruleText, sub2Pos, ruleText.length() - sub2Pos);
947 partialResult = matchToDelimiter(workText2, 0, partialResult, 1014 partialResult = matchToDelimiter(workText2, 0, partialResult,
948 temp, pp2, sub2, 1015 temp, pp2, sub2,
949 upperBound); 1016 upperBound);
950 1017
951 // if we got a successful match on this second 1018 // if we got a successful match on this second
952 // matchToDelimiter() call, update the high-water mark 1019 // matchToDelimiter() call, update the high-water mark
953 // and result (if necessary) 1020 // and result (if necessary)
954 if (pp2.getIndex() != 0 || sub2->isNullSubstitution()) { 1021 if (pp2.getIndex() != 0 || sub2 == NULL) {
955 if (prefixLength + pp.getIndex() + pp2.getIndex() > highWaterMar k) { 1022 if (prefixLength + pp.getIndex() + pp2.getIndex() > highWaterMar k) {
956 highWaterMark = prefixLength + pp.getIndex() + pp2.getIndex( ); 1023 highWaterMark = prefixLength + pp.getIndex() + pp2.getIndex( );
957 result = partialResult; 1024 result = partialResult;
958 } 1025 }
959 } 1026 }
960 // commented out because ParsePosition doesn't have error index in 1 .1.x
961 // restored for ICU4C port
962 else { 1027 else {
963 int32_t temp = pp2.getErrorIndex() + sub1->getPos() + pp.getInde x(); 1028 // commented out because ParsePosition doesn't have error index in 1.1.x
1029 // restored for ICU4C port
1030 int32_t temp = pp2.getErrorIndex() + sub1Pos + pp.getIndex();
964 if (temp> parsePosition.getErrorIndex()) { 1031 if (temp> parsePosition.getErrorIndex()) {
965 parsePosition.setErrorIndex(temp); 1032 parsePosition.setErrorIndex(temp);
966 } 1033 }
967 } 1034 }
968 } 1035 }
969 // commented out because ParsePosition doesn't have error index in 1.1.x
970 // restored for ICU4C port
971 else { 1036 else {
972 int32_t temp = sub1->getPos() + pp.getErrorIndex(); 1037 // commented out because ParsePosition doesn't have error index in 1 .1.x
1038 // restored for ICU4C port
1039 int32_t temp = sub1Pos + pp.getErrorIndex();
973 if (temp > parsePosition.getErrorIndex()) { 1040 if (temp > parsePosition.getErrorIndex()) {
974 parsePosition.setErrorIndex(temp); 1041 parsePosition.setErrorIndex(temp);
975 } 1042 }
976 } 1043 }
977 // keep trying to match things until the outer matchToDelimiter() 1044 // keep trying to match things until the outer matchToDelimiter()
978 // call fails to make a match (each time, it picks up where it 1045 // call fails to make a match (each time, it picks up where it
979 // left off the previous time) 1046 // left off the previous time)
980 } while (sub1->getPos() != sub2->getPos() 1047 } while (sub1Pos != sub2Pos
981 && pp.getIndex() > 0 1048 && pp.getIndex() > 0
982 && pp.getIndex() < workText.length() 1049 && pp.getIndex() < workText.length()
983 && pp.getIndex() != start); 1050 && pp.getIndex() != start);
984 1051
985 // update the caller's ParsePosition with our high-water mark 1052 // update the caller's ParsePosition with our high-water mark
986 // (i.e., it now points at the first character this function 1053 // (i.e., it now points at the first character this function
987 // didn't match-- the ParsePosition is therefore unchanged if 1054 // didn't match-- the ParsePosition is therefore unchanged if
988 // we didn't match anything) 1055 // we didn't match anything)
989 parsePosition.setIndex(highWaterMark); 1056 parsePosition.setIndex(highWaterMark);
990 // commented out because ParsePosition doesn't have error index in 1.1.x 1057 // commented out because ParsePosition doesn't have error index in 1.1.x
991 // restored for ICU4C port 1058 // restored for ICU4C port
992 if (highWaterMark > 0) { 1059 if (highWaterMark > 0) {
993 parsePosition.setErrorIndex(0); 1060 parsePosition.setErrorIndex(0);
994 } 1061 }
995 1062
996 // this is a hack for one unusual condition: Normally, whether this 1063 // this is a hack for one unusual condition: Normally, whether this
997 // rule belong to a fraction rule set or not is handled by its 1064 // rule belong to a fraction rule set or not is handled by its
998 // substitutions. But if that rule HAS NO substitutions, then 1065 // substitutions. But if that rule HAS NO substitutions, then
999 // we have to account for it here. By definition, if the matching 1066 // we have to account for it here. By definition, if the matching
1000 // rule in a fraction rule set has no substitutions, its numerator 1067 // rule in a fraction rule set has no substitutions, its numerator
1001 // is 1, and so the result is the reciprocal of its base value. 1068 // is 1, and so the result is the reciprocal of its base value.
1002 if (isFractionRule && 1069 if (isFractionRule && highWaterMark > 0 && sub1 == NULL) {
1003 highWaterMark > 0 &&
1004 sub1->isNullSubstitution()) {
1005 result = 1 / result; 1070 result = 1 / result;
1006 } 1071 }
1007 1072
1008 resVal.setDouble(result); 1073 resVal.setDouble(result);
1009 return TRUE; // ??? do we need to worry if it is a long or a double? 1074 return TRUE; // ??? do we need to worry if it is a long or a double?
1010 } 1075 }
1011 1076
1012 /** 1077 /**
1013 * This function is used by parse() to match the text being parsed 1078 * This function is used by parse() to match the text being parsed
1014 * against a possible prefix string. This function 1079 * against a possible prefix string. This function
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
1122 // if the substitution could match all the text up to 1187 // if the substitution could match all the text up to
1123 // where we found "delimiter", then this function has 1188 // where we found "delimiter", then this function has
1124 // a successful match. Bump the caller's parse position 1189 // a successful match. Bump the caller's parse position
1125 // to point to the first character after the text 1190 // to point to the first character after the text
1126 // that matches "delimiter", and return the result 1191 // that matches "delimiter", and return the result
1127 // we got from parsing the substitution. 1192 // we got from parsing the substitution.
1128 if (success && tempPP.getIndex() == dPos) { 1193 if (success && tempPP.getIndex() == dPos) {
1129 pp.setIndex(dPos + dLen); 1194 pp.setIndex(dPos + dLen);
1130 return result.getDouble(); 1195 return result.getDouble();
1131 } 1196 }
1132 // commented out because ParsePosition doesn't have error index in 1.1.x
1133 // restored for ICU4C port
1134 else { 1197 else {
1198 // commented out because ParsePosition doesn't have error in dex in 1.1.x
1199 // restored for ICU4C port
1135 if (tempPP.getErrorIndex() > 0) { 1200 if (tempPP.getErrorIndex() > 0) {
1136 pp.setErrorIndex(tempPP.getErrorIndex()); 1201 pp.setErrorIndex(tempPP.getErrorIndex());
1137 } else { 1202 } else {
1138 pp.setErrorIndex(tempPP.getIndex()); 1203 pp.setErrorIndex(tempPP.getIndex());
1139 } 1204 }
1140 } 1205 }
1141 } 1206 }
1142 1207
1143 // if we didn't match the substitution, search for another 1208 // if we didn't match the substitution, search for another
1144 // copy of "delimiter" in "text" and repeat the loop if 1209 // copy of "delimiter" in "text" and repeat the loop if
1145 // we find it 1210 // we find it
1146 tempPP.setIndex(0); 1211 tempPP.setIndex(0);
1147 dPos = findText(text, delimiter, dPos + dLen, &dLen); 1212 dPos = findText(text, delimiter, dPos + dLen, &dLen);
1148 } 1213 }
1149 // if we make it here, this was an unsuccessful match, and we 1214 // if we make it here, this was an unsuccessful match, and we
1150 // leave pp unchanged and return 0 1215 // leave pp unchanged and return 0
1151 pp.setIndex(0); 1216 pp.setIndex(0);
1152 return 0; 1217 return 0;
1153 1218
1154 // if "delimiter" is empty, or consists only of ignorable characters 1219 // if "delimiter" is empty, or consists only of ignorable characters
1155 // (i.e., is semantically empty), thwe we obviously can't search 1220 // (i.e., is semantically empty), thwe we obviously can't search
1156 // for "delimiter". Instead, just use "sub" to parse as much of 1221 // for "delimiter". Instead, just use "sub" to parse as much of
1157 // "text" as possible. 1222 // "text" as possible.
1158 } else { 1223 }
1224 else if (sub == NULL) {
1225 return _baseValue;
1226 }
1227 else {
1159 ParsePosition tempPP; 1228 ParsePosition tempPP;
1160 Formattable result; 1229 Formattable result;
1161 1230
1162 // try to match the whole string against the substitution 1231 // try to match the whole string against the substitution
1163 UBool success = sub->doParse(text, tempPP, _baseValue, upperBound, 1232 UBool success = sub->doParse(text, tempPP, _baseValue, upperBound,
1164 #if UCONFIG_NO_COLLATION 1233 #if UCONFIG_NO_COLLATION
1165 FALSE, 1234 FALSE,
1166 #else 1235 #else
1167 formatter->isLenient(), 1236 formatter->isLenient(),
1168 #endif 1237 #endif
1169 result); 1238 result);
1170 if (success && (tempPP.getIndex() != 0 || sub->isNullSubstitution())) { 1239 if (success && (tempPP.getIndex() != 0)) {
1171 // if there's a successful match (or it's a null 1240 // if there's a successful match (or it's a null
1172 // substitution), update pp to point to the first 1241 // substitution), update pp to point to the first
1173 // character we didn't match, and pass the result from 1242 // character we didn't match, and pass the result from
1174 // sub.doParse() on through to the caller 1243 // sub.doParse() on through to the caller
1175 pp.setIndex(tempPP.getIndex()); 1244 pp.setIndex(tempPP.getIndex());
1176 return result.getDouble(); 1245 return result.getDouble();
1177 } 1246 }
1178 // commented out because ParsePosition doesn't have error index in 1.1.x
1179 // restored for ICU4C port
1180 else { 1247 else {
1248 // commented out because ParsePosition doesn't have error index in 1 .1.x
1249 // restored for ICU4C port
1181 pp.setErrorIndex(tempPP.getErrorIndex()); 1250 pp.setErrorIndex(tempPP.getErrorIndex());
1182 } 1251 }
1183 1252
1184 // and if we get to here, then nothing matched, so we return 1253 // and if we get to here, then nothing matched, so we return
1185 // 0 and leave pp alone 1254 // 0 and leave pp alone
1186 return 0; 1255 return 0;
1187 } 1256 }
1188 } 1257 }
1189 1258
1190 /** 1259 /**
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after
1515 1584
1516 return o == CollationElementIterator::NULLORDER; 1585 return o == CollationElementIterator::NULLORDER;
1517 } 1586 }
1518 #endif 1587 #endif
1519 1588
1520 // if lenient parsing is turned off, there is no such thing as 1589 // if lenient parsing is turned off, there is no such thing as
1521 // an ignorable character: return true only if the string is empty 1590 // an ignorable character: return true only if the string is empty
1522 return FALSE; 1591 return FALSE;
1523 } 1592 }
1524 1593
1594 void
1595 NFRule::setDecimalFormatSymbols(const DecimalFormatSymbols& newSymbols, UErrorCo de& status) {
1596 if (sub1 != NULL) {
1597 sub1->setDecimalFormatSymbols(newSymbols, status);
1598 }
1599 if (sub2 != NULL) {
1600 sub2->setDecimalFormatSymbols(newSymbols, status);
1601 }
1602 }
1603
1525 U_NAMESPACE_END 1604 U_NAMESPACE_END
1526 1605
1527 /* U_HAVE_RBNF */ 1606 /* U_HAVE_RBNF */
1528 #endif 1607 #endif
OLDNEW
« no previous file with comments | « source/i18n/nfrule.h ('k') | source/i18n/nfsubs.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698