Imported Upstream version 58.1
[platform/upstream/icu.git] / source / i18n / nfsubs.cpp
1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 ******************************************************************************
5 *   Copyright (C) 1997-2015, International Business Machines
6 *   Corporation and others.  All Rights Reserved.
7 ******************************************************************************
8 *   file name:  nfsubs.cpp
9 *   encoding:   US-ASCII
10 *   tab size:   8 (not used)
11 *   indentation:4
12 *
13 * Modification history
14 * Date        Name      Comments
15 * 10/11/2001  Doug      Ported from ICU4J
16 */
17
18 #include <stdio.h>
19 #include "utypeinfo.h"  // for 'typeid' to work
20
21 #include "nfsubs.h"
22 #include "digitlst.h"
23
24 #if U_HAVE_RBNF
25
26 static const UChar gLessThan = 0x003c;
27 static const UChar gEquals = 0x003d;
28 static const UChar gGreaterThan = 0x003e;
29 static const UChar gPercent = 0x0025;
30 static const UChar gPound = 0x0023;
31 static const UChar gZero = 0x0030;
32 static const UChar gSpace = 0x0020;
33
34 static const UChar gEqualsEquals[] =
35 {
36     0x3D, 0x3D, 0
37 }; /* "==" */
38 static const UChar gGreaterGreaterGreaterThan[] =
39 {
40     0x3E, 0x3E, 0x3E, 0
41 }; /* ">>>" */
42 static const UChar gGreaterGreaterThan[] =
43 {
44     0x3E, 0x3E, 0
45 }; /* ">>" */
46
47 U_NAMESPACE_BEGIN
48
49 class SameValueSubstitution : public NFSubstitution {
50 public:
51     SameValueSubstitution(int32_t pos,
52         const NFRuleSet* ruleset,
53         const UnicodeString& description,
54         UErrorCode& status);
55     virtual ~SameValueSubstitution();
56
57     virtual int64_t transformNumber(int64_t number) const { return number; }
58     virtual double transformNumber(double number) const { return number; }
59     virtual double composeRuleValue(double newRuleValue, double /*oldRuleValue*/) const { return newRuleValue; }
60     virtual double calcUpperBound(double oldUpperBound) const { return oldUpperBound; }
61     virtual UChar tokenChar() const { return (UChar)0x003d; } // '='
62
63 public:
64     static UClassID getStaticClassID(void);
65     virtual UClassID getDynamicClassID(void) const;
66 };
67
68 SameValueSubstitution::~SameValueSubstitution() {}
69
70 class MultiplierSubstitution : public NFSubstitution {
71     double divisor;
72     int64_t ldivisor;
73
74 public:
75     MultiplierSubstitution(int32_t _pos,
76         double _divisor,
77         const NFRuleSet* _ruleSet,
78         const UnicodeString& description,
79         UErrorCode& status)
80         : NFSubstitution(_pos, _ruleSet, description, status), divisor(_divisor)
81     {
82         ldivisor = util64_fromDouble(divisor);
83         if (divisor == 0) {
84             status = U_PARSE_ERROR;
85         }
86     }
87     virtual ~MultiplierSubstitution();
88
89     virtual void setDivisor(int32_t radix, int32_t exponent, UErrorCode& status) { 
90         divisor = uprv_pow(radix, exponent);
91         ldivisor = util64_fromDouble(divisor);
92
93         if(divisor == 0) {
94             status = U_PARSE_ERROR;
95         }
96     }
97
98     virtual UBool operator==(const NFSubstitution& rhs) const;
99
100     virtual int64_t transformNumber(int64_t number) const {
101         return number / ldivisor;
102     }
103
104     virtual double transformNumber(double number) const {
105         if (getRuleSet()) {
106             return uprv_floor(number / divisor);
107         } else {
108             return number/divisor;
109         }
110     }
111
112     virtual double composeRuleValue(double newRuleValue, double /*oldRuleValue*/) const {
113         return newRuleValue * divisor;
114     }
115
116     virtual double calcUpperBound(double /*oldUpperBound*/) const { return divisor; }
117
118     virtual UChar tokenChar() const { return (UChar)0x003c; } // '<'
119
120 public:
121     static UClassID getStaticClassID(void);
122     virtual UClassID getDynamicClassID(void) const;
123 };
124
125 MultiplierSubstitution::~MultiplierSubstitution() {}
126
127 class ModulusSubstitution : public NFSubstitution {
128     double divisor;
129     int64_t  ldivisor;
130     const NFRule* ruleToUse;
131 public:
132     ModulusSubstitution(int32_t pos,
133         double _divisor,
134         const NFRule* rulePredecessor,
135         const NFRuleSet* ruleSet,
136         const UnicodeString& description,
137         UErrorCode& status);
138     virtual ~ModulusSubstitution();
139
140     virtual void setDivisor(int32_t radix, int32_t exponent, UErrorCode& status) { 
141         divisor = uprv_pow(radix, exponent);
142         ldivisor = util64_fromDouble(divisor);
143
144         if (divisor == 0) {
145             status = U_PARSE_ERROR;
146         }
147     }
148
149     virtual UBool operator==(const NFSubstitution& rhs) const;
150
151     virtual void doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t pos, int32_t recursionCount, UErrorCode& status) const;
152     virtual void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos, int32_t recursionCount, UErrorCode& status) const;
153
154     virtual int64_t transformNumber(int64_t number) const { return number % ldivisor; }
155     virtual double transformNumber(double number) const { return uprv_fmod(number, divisor); }
156
157     virtual UBool doParse(const UnicodeString& text, 
158         ParsePosition& parsePosition,
159         double baseValue,
160         double upperBound,
161         UBool lenientParse,
162         Formattable& result) const;
163
164     virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const {
165         return oldRuleValue - uprv_fmod(oldRuleValue, divisor) + newRuleValue;
166     }
167
168     virtual double calcUpperBound(double /*oldUpperBound*/) const { return divisor; }
169
170     virtual UBool isModulusSubstitution() const { return TRUE; }
171
172     virtual UChar tokenChar() const { return (UChar)0x003e; } // '>'
173
174         virtual void toString(UnicodeString& result) const;
175
176 public:
177     static UClassID getStaticClassID(void);
178     virtual UClassID getDynamicClassID(void) const;
179 };
180
181 ModulusSubstitution::~ModulusSubstitution() {}
182
183 class IntegralPartSubstitution : public NFSubstitution {
184 public:
185     IntegralPartSubstitution(int32_t _pos,
186         const NFRuleSet* _ruleSet,
187         const UnicodeString& description,
188         UErrorCode& status)
189         : NFSubstitution(_pos, _ruleSet, description, status) {}
190     virtual ~IntegralPartSubstitution();
191
192     virtual int64_t transformNumber(int64_t number) const { return number; }
193     virtual double transformNumber(double number) const { return uprv_floor(number); }
194     virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const { return newRuleValue + oldRuleValue; }
195     virtual double calcUpperBound(double /*oldUpperBound*/) const { return DBL_MAX; }
196     virtual UChar tokenChar() const { return (UChar)0x003c; } // '<'
197
198 public:
199     static UClassID getStaticClassID(void);
200     virtual UClassID getDynamicClassID(void) const;
201 };
202
203 IntegralPartSubstitution::~IntegralPartSubstitution() {}
204
205 class FractionalPartSubstitution : public NFSubstitution {
206     UBool byDigits;
207     UBool useSpaces;
208     enum { kMaxDecimalDigits = 8 };
209 public:
210     FractionalPartSubstitution(int32_t pos,
211         const NFRuleSet* ruleSet,
212         const UnicodeString& description,
213         UErrorCode& status);
214     virtual ~FractionalPartSubstitution();
215
216     virtual UBool operator==(const NFSubstitution& rhs) const;
217
218     virtual void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos, int32_t recursionCount, UErrorCode& status) const;
219     virtual void doSubstitution(int64_t /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/, int32_t /*recursionCount*/, UErrorCode& /*status*/) const {}
220     virtual int64_t transformNumber(int64_t /*number*/) const { return 0; }
221     virtual double transformNumber(double number) const { return number - uprv_floor(number); }
222
223     virtual UBool doParse(const UnicodeString& text,
224         ParsePosition& parsePosition,
225         double baseValue,
226         double upperBound,
227         UBool lenientParse,
228         Formattable& result) const;
229
230     virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const { return newRuleValue + oldRuleValue; }
231     virtual double calcUpperBound(double /*oldUpperBound*/) const { return 0.0; }
232     virtual UChar tokenChar() const { return (UChar)0x003e; } // '>'
233
234 public:
235     static UClassID getStaticClassID(void);
236     virtual UClassID getDynamicClassID(void) const;
237 };
238
239 FractionalPartSubstitution::~FractionalPartSubstitution() {}
240
241 class AbsoluteValueSubstitution : public NFSubstitution {
242 public:
243     AbsoluteValueSubstitution(int32_t _pos,
244         const NFRuleSet* _ruleSet,
245         const UnicodeString& description,
246         UErrorCode& status)
247         : NFSubstitution(_pos, _ruleSet, description, status) {}
248     virtual ~AbsoluteValueSubstitution();
249
250     virtual int64_t transformNumber(int64_t number) const { return number >= 0 ? number : -number; }
251     virtual double transformNumber(double number) const { return uprv_fabs(number); }
252     virtual double composeRuleValue(double newRuleValue, double /*oldRuleValue*/) const { return -newRuleValue; }
253     virtual double calcUpperBound(double /*oldUpperBound*/) const { return DBL_MAX; }
254     virtual UChar tokenChar() const { return (UChar)0x003e; } // '>'
255
256 public:
257     static UClassID getStaticClassID(void);
258     virtual UClassID getDynamicClassID(void) const;
259 };
260
261 AbsoluteValueSubstitution::~AbsoluteValueSubstitution() {}
262
263 class NumeratorSubstitution : public NFSubstitution {
264     double denominator;
265     int64_t ldenominator;
266     UBool withZeros;
267 public:
268     static inline UnicodeString fixdesc(const UnicodeString& desc) {
269         if (desc.endsWith(LTLT, 2)) {
270             UnicodeString result(desc, 0, desc.length()-1);
271             return result;
272         }
273         return desc;
274     }
275     NumeratorSubstitution(int32_t _pos,
276         double _denominator,
277         NFRuleSet* _ruleSet,
278         const UnicodeString& description,
279         UErrorCode& status)
280         : NFSubstitution(_pos, _ruleSet, fixdesc(description), status), denominator(_denominator) 
281     {
282         ldenominator = util64_fromDouble(denominator);
283         withZeros = description.endsWith(LTLT, 2);
284     }
285     virtual ~NumeratorSubstitution();
286
287     virtual UBool operator==(const NFSubstitution& rhs) const;
288
289     virtual int64_t transformNumber(int64_t number) const { return number * ldenominator; }
290     virtual double transformNumber(double number) const { return uprv_round(number * denominator); }
291
292     virtual void doSubstitution(int64_t /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/, int32_t /*recursionCount*/, UErrorCode& /*status*/) const {}
293     virtual void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos, int32_t recursionCount, UErrorCode& status) const;
294     virtual UBool doParse(const UnicodeString& text, 
295         ParsePosition& parsePosition,
296         double baseValue,
297         double upperBound,
298         UBool /*lenientParse*/,
299         Formattable& result) const;
300
301     virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const { return newRuleValue / oldRuleValue; }
302     virtual double calcUpperBound(double /*oldUpperBound*/) const { return denominator; }
303     virtual UChar tokenChar() const { return (UChar)0x003c; } // '<'
304 private:
305     static const UChar LTLT[2];
306
307 public:
308     static UClassID getStaticClassID(void);
309     virtual UClassID getDynamicClassID(void) const;
310 };
311
312 NumeratorSubstitution::~NumeratorSubstitution() {}
313
314 NFSubstitution*
315 NFSubstitution::makeSubstitution(int32_t pos,
316                                  const NFRule* rule,
317                                  const NFRule* predecessor,
318                                  const NFRuleSet* ruleSet,
319                                  const RuleBasedNumberFormat* formatter,
320                                  const UnicodeString& description,
321                                  UErrorCode& status)
322 {
323     // if the description is empty, return a NullSubstitution
324     if (description.length() == 0) {
325         return NULL;
326     }
327
328     switch (description.charAt(0)) {
329         // if the description begins with '<'...
330     case gLessThan:
331         // throw an exception if the rule is a negative number
332         // rule
333         if (rule->getBaseValue() == NFRule::kNegativeNumberRule) {
334             // throw new IllegalArgumentException("<< not allowed in negative-number rule");
335             status = U_PARSE_ERROR;
336             return NULL;
337         }
338
339         // if the rule is a fraction rule, return an
340         // IntegralPartSubstitution
341         else if (rule->getBaseValue() == NFRule::kImproperFractionRule
342             || rule->getBaseValue() == NFRule::kProperFractionRule
343             || rule->getBaseValue() == NFRule::kMasterRule) {
344             return new IntegralPartSubstitution(pos, ruleSet, description, status);
345         }
346
347         // if the rule set containing the rule is a fraction
348         // rule set, return a NumeratorSubstitution
349         else if (ruleSet->isFractionRuleSet()) {
350             return new NumeratorSubstitution(pos, (double)rule->getBaseValue(),
351                 formatter->getDefaultRuleSet(), description, status);
352         }
353
354         // otherwise, return a MultiplierSubstitution
355         else {
356             return new MultiplierSubstitution(pos, rule->getDivisor(), ruleSet,
357                 description, status);
358         }
359
360         // if the description begins with '>'...
361     case gGreaterThan:
362         // if the rule is a negative-number rule, return
363         // an AbsoluteValueSubstitution
364         if (rule->getBaseValue() == NFRule::kNegativeNumberRule) {
365             return new AbsoluteValueSubstitution(pos, ruleSet, description, status);
366         }
367
368         // if the rule is a fraction rule, return a
369         // FractionalPartSubstitution
370         else if (rule->getBaseValue() == NFRule::kImproperFractionRule
371             || rule->getBaseValue() == NFRule::kProperFractionRule
372             || rule->getBaseValue() == NFRule::kMasterRule) {
373             return new FractionalPartSubstitution(pos, ruleSet, description, status);
374         }
375
376         // if the rule set owning the rule is a fraction rule set,
377         // throw an exception
378         else if (ruleSet->isFractionRuleSet()) {
379             // throw new IllegalArgumentException(">> not allowed in fraction rule set");
380             status = U_PARSE_ERROR;
381             return NULL;
382         }
383
384         // otherwise, return a ModulusSubstitution
385         else {
386             return new ModulusSubstitution(pos, rule->getDivisor(), predecessor,
387                 ruleSet, description, status);
388         }
389
390         // if the description begins with '=', always return a
391         // SameValueSubstitution
392     case gEquals:
393         return new SameValueSubstitution(pos, ruleSet, description, status);
394
395         // and if it's anything else, throw an exception
396     default:
397         // throw new IllegalArgumentException("Illegal substitution character");
398         status = U_PARSE_ERROR;
399     }
400     return NULL;
401 }
402
403 NFSubstitution::NFSubstitution(int32_t _pos,
404                                const NFRuleSet* _ruleSet,
405                                const UnicodeString& description,
406                                UErrorCode& status)
407                                : pos(_pos), ruleSet(NULL), numberFormat(NULL)
408 {
409     // the description should begin and end with the same character.
410     // If it doesn't that's a syntax error.  Otherwise,
411     // makeSubstitution() was the only thing that needed to know
412     // about these characters, so strip them off
413     UnicodeString workingDescription(description);
414     if (description.length() >= 2
415         && description.charAt(0) == description.charAt(description.length() - 1))
416     {
417         workingDescription.remove(description.length() - 1, 1);
418         workingDescription.remove(0, 1);
419     }
420     else if (description.length() != 0) {
421         // throw new IllegalArgumentException("Illegal substitution syntax");
422         status = U_PARSE_ERROR;
423         return;
424     }
425
426     if (workingDescription.length() == 0) {
427         // if the description was just two paired token characters
428         // (i.e., "<<" or ">>"), it uses the rule set it belongs to to
429         // format its result
430         this->ruleSet = _ruleSet;
431     }
432     else if (workingDescription.charAt(0) == gPercent) {
433         // if the description contains a rule set name, that's the rule
434         // set we use to format the result: get a reference to the
435         // names rule set
436         this->ruleSet = _ruleSet->getOwner()->findRuleSet(workingDescription, status);
437     }
438     else if (workingDescription.charAt(0) == gPound || workingDescription.charAt(0) ==gZero) {
439         // if the description begins with 0 or #, treat it as a
440         // DecimalFormat pattern, and initialize a DecimalFormat with
441         // that pattern (then set it to use the DecimalFormatSymbols
442         // belonging to our formatter)
443         const DecimalFormatSymbols* sym = _ruleSet->getOwner()->getDecimalFormatSymbols();
444         if (!sym) {
445             status = U_MISSING_RESOURCE_ERROR;
446             return;
447         }
448         DecimalFormat *tempNumberFormat = new DecimalFormat(workingDescription, *sym, status);
449         /* test for NULL */
450         if (!tempNumberFormat) {
451             status = U_MEMORY_ALLOCATION_ERROR;
452             return;
453         }
454         if (U_FAILURE(status)) {
455             delete tempNumberFormat;
456             return;
457         }
458         this->numberFormat = tempNumberFormat;
459     }
460     else if (workingDescription.charAt(0) == gGreaterThan) {
461         // if the description is ">>>", this substitution bypasses the
462         // usual rule-search process and always uses the rule that precedes
463         // it in its own rule set's rule list (this is used for place-value
464         // notations: formats where you want to see a particular part of
465         // a number even when it's 0)
466
467         // this causes problems when >>> is used in a frationalPartSubstitution
468         // this->ruleSet = NULL;
469         this->ruleSet = _ruleSet;
470         this->numberFormat = NULL;
471     }
472     else {
473         // and of the description is none of these things, it's a syntax error
474
475         // throw new IllegalArgumentException("Illegal substitution syntax");
476         status = U_PARSE_ERROR;
477     }
478 }
479
480 NFSubstitution::~NFSubstitution()
481 {
482     delete numberFormat;
483     numberFormat = NULL;
484 }
485
486 /**
487  * Set's the substitution's divisor.  Used by NFRule.setBaseValue().
488  * A no-op for all substitutions except multiplier and modulus
489  * substitutions.
490  * @param radix The radix of the divisor
491  * @param exponent The exponent of the divisor
492  */
493 void
494 NFSubstitution::setDivisor(int32_t /*radix*/, int32_t /*exponent*/, UErrorCode& /*status*/) {
495   // a no-op for all substitutions except multiplier and modulus substitutions
496 }
497
498 void
499 NFSubstitution::setDecimalFormatSymbols(const DecimalFormatSymbols &newSymbols, UErrorCode& /*status*/) {
500     if (numberFormat != NULL) {
501         numberFormat->setDecimalFormatSymbols(newSymbols);
502     }
503 }
504
505 //-----------------------------------------------------------------------
506 // boilerplate
507 //-----------------------------------------------------------------------
508
509 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NFSubstitution)
510
511 /**
512  * Compares two substitutions for equality
513  * @param The substitution to compare this one to
514  * @return true if the two substitutions are functionally equivalent
515  */
516 UBool
517 NFSubstitution::operator==(const NFSubstitution& rhs) const
518 {
519   // compare class and all of the fields all substitutions have
520   // in common
521   // this should be called by subclasses before their own equality tests
522   return typeid(*this) == typeid(rhs)
523   && pos == rhs.pos
524   && (ruleSet == NULL) == (rhs.ruleSet == NULL)
525   // && ruleSet == rhs.ruleSet causes circularity, other checks to make instead?
526   && (numberFormat == NULL
527       ? (rhs.numberFormat == NULL)
528       : (*numberFormat == *rhs.numberFormat));
529 }
530
531 /**
532  * Returns a textual description of the substitution
533  * @return A textual description of the substitution.  This might
534  * not be identical to the description it was created from, but
535  * it'll produce the same result.
536  */
537 void
538 NFSubstitution::toString(UnicodeString& text) const
539 {
540   // use tokenChar() to get the character at the beginning and
541   // end of the substitutin token.  In between them will go
542   // either the name of the rule set it uses, or the pattern of
543   // the DecimalFormat it uses
544   text.remove();
545   text.append(tokenChar());
546
547   UnicodeString temp;
548   if (ruleSet != NULL) {
549     ruleSet->getName(temp);
550   } else if (numberFormat != NULL) {
551     numberFormat->toPattern(temp);
552   }
553   text.append(temp);
554   text.append(tokenChar());
555 }
556
557 //-----------------------------------------------------------------------
558 // formatting
559 //-----------------------------------------------------------------------
560
561 /**
562  * Performs a mathematical operation on the number, formats it using
563  * either ruleSet or decimalFormat, and inserts the result into
564  * toInsertInto.
565  * @param number The number being formatted.
566  * @param toInsertInto The string we insert the result into
567  * @param pos The position in toInsertInto where the owning rule's
568  * rule text begins (this value is added to this substitution's
569  * position to determine exactly where to insert the new text)
570  */
571 void
572 NFSubstitution::doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t _pos, int32_t recursionCount, UErrorCode& status) const
573 {
574     if (ruleSet != NULL) {
575         // perform a transformation on the number that is dependent
576         // on the type of substitution this is, then just call its
577         // rule set's format() method to format the result
578         ruleSet->format(transformNumber(number), toInsertInto, _pos + this->pos, recursionCount, status);
579     } else if (numberFormat != NULL) {
580         // or perform the transformation on the number (preserving
581         // the result's fractional part if the formatter it set
582         // to show it), then use that formatter's format() method
583         // to format the result
584         double numberToFormat = transformNumber((double)number);
585         if (numberFormat->getMaximumFractionDigits() == 0) {
586             numberToFormat = uprv_floor(numberToFormat);
587         }
588
589         UnicodeString temp;
590         numberFormat->format(numberToFormat, temp, status);
591         toInsertInto.insert(_pos + this->pos, temp);
592     }
593 }
594
595 /**
596  * Performs a mathematical operation on the number, formats it using
597  * either ruleSet or decimalFormat, and inserts the result into
598  * toInsertInto.
599  * @param number The number being formatted.
600  * @param toInsertInto The string we insert the result into
601  * @param pos The position in toInsertInto where the owning rule's
602  * rule text begins (this value is added to this substitution's
603  * position to determine exactly where to insert the new text)
604  */
605 void
606 NFSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos, int32_t recursionCount, UErrorCode& status) const {
607     // perform a transformation on the number being formatted that
608     // is dependent on the type of substitution this is
609     double numberToFormat = transformNumber(number);
610
611     if (uprv_isInfinite(numberToFormat)) {
612         // This is probably a minus rule. Combine it with an infinite rule.
613         const NFRule *infiniteRule = ruleSet->findDoubleRule(uprv_getInfinity());
614         infiniteRule->doFormat(numberToFormat, toInsertInto, _pos + this->pos, recursionCount, status);
615         return;
616     }
617
618     // if the result is an integer, from here on out we work in integer
619     // space (saving time and memory and preserving accuracy)
620     if (numberToFormat == uprv_floor(numberToFormat) && ruleSet != NULL) {
621         ruleSet->format(util64_fromDouble(numberToFormat), toInsertInto, _pos + this->pos, recursionCount, status);
622
623         // if the result isn't an integer, then call either our rule set's
624         // format() method or our DecimalFormat's format() method to
625         // format the result
626     } else {
627         if (ruleSet != NULL) {
628             ruleSet->format(numberToFormat, toInsertInto, _pos + this->pos, recursionCount, status);
629         } else if (numberFormat != NULL) {
630             UnicodeString temp;
631             numberFormat->format(numberToFormat, temp);
632             toInsertInto.insert(_pos + this->pos, temp);
633         }
634     }
635 }
636
637
638     //-----------------------------------------------------------------------
639     // parsing
640     //-----------------------------------------------------------------------
641
642 #ifdef RBNF_DEBUG
643 #include <stdio.h>
644 #endif
645
646 /**
647  * Parses a string using the rule set or DecimalFormat belonging
648  * to this substitution.  If there's a match, a mathematical
649  * operation (the inverse of the one used in formatting) is
650  * performed on the result of the parse and the value passed in
651  * and returned as the result.  The parse position is updated to
652  * point to the first unmatched character in the string.
653  * @param text The string to parse
654  * @param parsePosition On entry, ignored, but assumed to be 0.
655  * On exit, this is updated to point to the first unmatched
656  * character (or 0 if the substitution didn't match)
657  * @param baseValue A partial parse result that should be
658  * combined with the result of this parse
659  * @param upperBound When searching the rule set for a rule
660  * matching the string passed in, only rules with base values
661  * lower than this are considered
662  * @param lenientParse If true and matching against rules fails,
663  * the substitution will also try matching the text against
664  * numerals using a default-costructed NumberFormat.  If false,
665  * no extra work is done.  (This value is false whenever the
666  * formatter isn't in lenient-parse mode, but is also false
667  * under some conditions even when the formatter _is_ in
668  * lenient-parse mode.)
669  * @return If there's a match, this is the result of composing
670  * baseValue with whatever was returned from matching the
671  * characters.  This will be either a Long or a Double.  If there's
672  * no match this is new Long(0) (not null), and parsePosition
673  * is left unchanged.
674  */
675 UBool
676 NFSubstitution::doParse(const UnicodeString& text,
677                         ParsePosition& parsePosition,
678                         double baseValue,
679                         double upperBound,
680                         UBool lenientParse,
681                         Formattable& result) const
682 {
683 #ifdef RBNF_DEBUG
684     fprintf(stderr, "<nfsubs> %x bv: %g ub: %g\n", this, baseValue, upperBound);
685 #endif
686     // figure out the highest base value a rule can have and match
687     // the text being parsed (this varies according to the type of
688     // substitutions: multiplier, modulus, and numerator substitutions
689     // restrict the search to rules with base values lower than their
690     // own; same-value substitutions leave the upper bound wherever
691     // it was, and the others allow any rule to match
692     upperBound = calcUpperBound(upperBound);
693
694     // use our rule set to parse the text.  If that fails and
695     // lenient parsing is enabled (this is always false if the
696     // formatter's lenient-parsing mode is off, but it may also
697     // be false even when the formatter's lenient-parse mode is
698     // on), then also try parsing the text using a default-
699     // constructed NumberFormat
700     if (ruleSet != NULL) {
701         ruleSet->parse(text, parsePosition, upperBound, result);
702         if (lenientParse && !ruleSet->isFractionRuleSet() && parsePosition.getIndex() == 0) {
703             UErrorCode status = U_ZERO_ERROR;
704             NumberFormat* fmt = NumberFormat::createInstance(status);
705             if (U_SUCCESS(status)) {
706                 fmt->parse(text, result, parsePosition);
707             }
708             delete fmt;
709         }
710
711         // ...or use our DecimalFormat to parse the text
712     } else if (numberFormat != NULL) {
713         numberFormat->parse(text, result, parsePosition);
714     }
715
716     // if the parse was successful, we've already advanced the caller's
717     // parse position (this is the one function that doesn't have one
718     // of its own).  Derive a parse result and return it as a Long,
719     // if possible, or a Double
720     if (parsePosition.getIndex() != 0) {
721         UErrorCode status = U_ZERO_ERROR;
722         double tempResult = result.getDouble(status);
723
724         // composeRuleValue() produces a full parse result from
725         // the partial parse result passed to this function from
726         // the caller (this is either the owning rule's base value
727         // or the partial result obtained from composing the
728         // owning rule's base value with its other substitution's
729         // parse result) and the partial parse result obtained by
730         // matching the substitution (which will be the same value
731         // the caller would get by parsing just this part of the
732         // text with RuleBasedNumberFormat.parse() ).  How the two
733         // values are used to derive the full parse result depends
734         // on the types of substitutions: For a regular rule, the
735         // ultimate result is its multiplier substitution's result
736         // times the rule's divisor (or the rule's base value) plus
737         // the modulus substitution's result (which will actually
738         // supersede part of the rule's base value).  For a negative-
739         // number rule, the result is the negative of its substitution's
740         // result.  For a fraction rule, it's the sum of its two
741         // substitution results.  For a rule in a fraction rule set,
742         // it's the numerator substitution's result divided by
743         // the rule's base value.  Results from same-value substitutions
744         // propagate back upard, and null substitutions don't affect
745         // the result.
746         tempResult = composeRuleValue(tempResult, baseValue);
747         result.setDouble(tempResult);
748         return TRUE;
749         // if the parse was UNsuccessful, return 0
750     } else {
751         result.setLong(0);
752         return FALSE;
753     }
754 }
755
756     /**
757      * Returns true if this is a modulus substitution.  (We didn't do this
758      * with instanceof partially because it causes source files to
759      * proliferate and partially because we have to port this to C++.)
760      * @return true if this object is an instance of ModulusSubstitution
761      */
762 UBool
763 NFSubstitution::isModulusSubstitution() const {
764     return FALSE;
765 }
766
767 //===================================================================
768 // SameValueSubstitution
769 //===================================================================
770
771 /**
772  * A substitution that passes the value passed to it through unchanged.
773  * Represented by == in rule descriptions.
774  */
775 SameValueSubstitution::SameValueSubstitution(int32_t _pos,
776                         const NFRuleSet* _ruleSet,
777                         const UnicodeString& description,
778                         UErrorCode& status)
779 : NFSubstitution(_pos, _ruleSet, description, status)
780 {
781     if (0 == description.compare(gEqualsEquals, 2)) {
782         // throw new IllegalArgumentException("== is not a legal token");
783         status = U_PARSE_ERROR;
784     }
785 }
786
787 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SameValueSubstitution)
788
789 //===================================================================
790 // MultiplierSubstitution
791 //===================================================================
792
793 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MultiplierSubstitution)
794
795 UBool MultiplierSubstitution::operator==(const NFSubstitution& rhs) const
796 {
797     return NFSubstitution::operator==(rhs) &&
798         divisor == ((const MultiplierSubstitution*)&rhs)->divisor;
799 }
800
801
802 //===================================================================
803 // ModulusSubstitution
804 //===================================================================
805
806 /**
807  * A substitution that divides the number being formatted by the its rule's
808  * divisor and formats the remainder.  Represented by "&gt;&gt;" in a
809  * regular rule.
810  */
811 ModulusSubstitution::ModulusSubstitution(int32_t _pos,
812                                          double _divisor,
813                                          const NFRule* predecessor,
814                                          const NFRuleSet* _ruleSet,
815                                          const UnicodeString& description,
816                                          UErrorCode& status)
817  : NFSubstitution(_pos, _ruleSet, description, status)
818  , divisor(_divisor)
819  , ruleToUse(NULL)
820 {
821   ldivisor = util64_fromDouble(_divisor);
822
823   // the owning rule's divisor controls the behavior of this
824   // substitution: rather than keeping a backpointer to the rule,
825   // we keep a copy of the divisor
826
827   if (ldivisor == 0) {
828       status = U_PARSE_ERROR;
829   }
830
831   if (0 == description.compare(gGreaterGreaterGreaterThan, 3)) {
832     // the >>> token doesn't alter how this substituion calculates the
833     // values it uses for formatting and parsing, but it changes
834     // what's done with that value after it's obtained: >>> short-
835     // circuits the rule-search process and goes straight to the
836     // specified rule to format the substitution value
837     ruleToUse = predecessor;
838   }
839 }
840
841 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ModulusSubstitution)
842
843 UBool ModulusSubstitution::operator==(const NFSubstitution& rhs) const
844 {
845   return NFSubstitution::operator==(rhs) &&
846   divisor == ((const ModulusSubstitution*)&rhs)->divisor &&
847   ruleToUse == ((const ModulusSubstitution*)&rhs)->ruleToUse;
848 }
849
850 //-----------------------------------------------------------------------
851 // formatting
852 //-----------------------------------------------------------------------
853
854
855 /**
856  * If this is a &gt;&gt;&gt; substitution, use ruleToUse to fill in
857  * the substitution.  Otherwise, just use the superclass function.
858  * @param number The number being formatted
859  * @toInsertInto The string to insert the result of this substitution
860  * into
861  * @param pos The position of the rule text in toInsertInto
862  */
863 void
864 ModulusSubstitution::doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t _pos, int32_t recursionCount, UErrorCode& status) const
865 {
866     // if this isn't a >>> substitution, just use the inherited version
867     // of this function (which uses either a rule set or a DecimalFormat
868     // to format its substitution value)
869     if (ruleToUse == NULL) {
870         NFSubstitution::doSubstitution(number, toInsertInto, _pos, recursionCount, status);
871
872         // a >>> substitution goes straight to a particular rule to
873         // format the substitution value
874     } else {
875         int64_t numberToFormat = transformNumber(number);
876         ruleToUse->doFormat(numberToFormat, toInsertInto, _pos + getPos(), recursionCount, status);
877     }
878 }
879
880 /**
881 * If this is a &gt;&gt;&gt; substitution, use ruleToUse to fill in
882 * the substitution.  Otherwise, just use the superclass function.
883 * @param number The number being formatted
884 * @toInsertInto The string to insert the result of this substitution
885 * into
886 * @param pos The position of the rule text in toInsertInto
887 */
888 void
889 ModulusSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos, int32_t recursionCount, UErrorCode& status) const
890 {
891     // if this isn't a >>> substitution, just use the inherited version
892     // of this function (which uses either a rule set or a DecimalFormat
893     // to format its substitution value)
894     if (ruleToUse == NULL) {
895         NFSubstitution::doSubstitution(number, toInsertInto, _pos, recursionCount, status);
896
897         // a >>> substitution goes straight to a particular rule to
898         // format the substitution value
899     } else {
900         double numberToFormat = transformNumber(number);
901
902         ruleToUse->doFormat(numberToFormat, toInsertInto, _pos + getPos(), recursionCount, status);
903     }
904 }
905
906 //-----------------------------------------------------------------------
907 // parsing
908 //-----------------------------------------------------------------------
909
910 /**
911  * If this is a &gt;&gt;&gt; substitution, match only against ruleToUse.
912  * Otherwise, use the superclass function.
913  * @param text The string to parse
914  * @param parsePosition Ignored on entry, updated on exit to point to
915  * the first unmatched character.
916  * @param baseValue The partial parse result prior to calling this
917  * routine.
918  */
919 UBool
920 ModulusSubstitution::doParse(const UnicodeString& text,
921                              ParsePosition& parsePosition,
922                              double baseValue,
923                              double upperBound,
924                              UBool lenientParse,
925                              Formattable& result) const
926 {
927     // if this isn't a >>> substitution, we can just use the
928     // inherited parse() routine to do the parsing
929     if (ruleToUse == NULL) {
930         return NFSubstitution::doParse(text, parsePosition, baseValue, upperBound, lenientParse, result);
931
932         // but if it IS a >>> substitution, we have to do it here: we
933         // use the specific rule's doParse() method, and then we have to
934         // do some of the other work of NFRuleSet.parse()
935     } else {
936         ruleToUse->doParse(text, parsePosition, FALSE, upperBound, result);
937
938         if (parsePosition.getIndex() != 0) {
939             UErrorCode status = U_ZERO_ERROR;
940             double tempResult = result.getDouble(status);
941             tempResult = composeRuleValue(tempResult, baseValue);
942             result.setDouble(tempResult);
943         }
944
945         return TRUE;
946     }
947 }
948 /**
949  * Returns a textual description of the substitution
950  * @return A textual description of the substitution.  This might
951  * not be identical to the description it was created from, but
952  * it'll produce the same result.
953  */
954 void
955 ModulusSubstitution::toString(UnicodeString& text) const
956 {
957   // use tokenChar() to get the character at the beginning and
958   // end of the substitutin token.  In between them will go
959   // either the name of the rule set it uses, or the pattern of
960   // the DecimalFormat it uses
961
962   if ( ruleToUse != NULL ) { // Must have been a >>> substitution.
963       text.remove();
964       text.append(tokenChar());
965       text.append(tokenChar());
966       text.append(tokenChar());
967   } else { // Otherwise just use the super-class function.
968           NFSubstitution::toString(text);
969   }
970 }
971 //===================================================================
972 // IntegralPartSubstitution
973 //===================================================================
974
975 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IntegralPartSubstitution)
976
977
978 //===================================================================
979 // FractionalPartSubstitution
980 //===================================================================
981
982
983     /**
984      * Constructs a FractionalPartSubstitution.  This object keeps a flag
985      * telling whether it should format by digits or not.  In addition,
986      * it marks the rule set it calls (if any) as a fraction rule set.
987      */
988 FractionalPartSubstitution::FractionalPartSubstitution(int32_t _pos,
989                              const NFRuleSet* _ruleSet,
990                              const UnicodeString& description,
991                              UErrorCode& status)
992  : NFSubstitution(_pos, _ruleSet, description, status)
993  , byDigits(FALSE)
994  , useSpaces(TRUE)
995
996 {
997     // akk, ruleSet can change in superclass constructor
998     if (0 == description.compare(gGreaterGreaterThan, 2) ||
999         0 == description.compare(gGreaterGreaterGreaterThan, 3) ||
1000         _ruleSet == getRuleSet()) {
1001         byDigits = TRUE;
1002         if (0 == description.compare(gGreaterGreaterGreaterThan, 3)) {
1003             useSpaces = FALSE;
1004         }
1005     } else {
1006         // cast away const
1007         ((NFRuleSet*)getRuleSet())->makeIntoFractionRuleSet();
1008     }
1009 }
1010
1011 //-----------------------------------------------------------------------
1012 // formatting
1013 //-----------------------------------------------------------------------
1014
1015 /**
1016  * If in "by digits" mode, fills in the substitution one decimal digit
1017  * at a time using the rule set containing this substitution.
1018  * Otherwise, uses the superclass function.
1019  * @param number The number being formatted
1020  * @param toInsertInto The string to insert the result of formatting
1021  * the substitution into
1022  * @param pos The position of the owning rule's rule text in
1023  * toInsertInto
1024  */
1025 void
1026 FractionalPartSubstitution::doSubstitution(double number, UnicodeString& toInsertInto,
1027                                            int32_t _pos, int32_t recursionCount, UErrorCode& status) const
1028 {
1029   // if we're not in "byDigits" mode, just use the inherited
1030   // doSubstitution() routine
1031   if (!byDigits) {
1032     NFSubstitution::doSubstitution(number, toInsertInto, _pos, recursionCount, status);
1033
1034     // if we're in "byDigits" mode, transform the value into an integer
1035     // by moving the decimal point eight places to the right and
1036     // pulling digits off the right one at a time, formatting each digit
1037     // as an integer using this substitution's owning rule set
1038     // (this is slower, but more accurate, than doing it from the
1039     // other end)
1040   } else {
1041     //          int32_t numberToFormat = (int32_t)uprv_round(transformNumber(number) * uprv_pow(10, kMaxDecimalDigits));
1042     //          // this flag keeps us from formatting trailing zeros.  It starts
1043     //          // out false because we're pulling from the right, and switches
1044     //          // to true the first time we encounter a non-zero digit
1045     //          UBool doZeros = FALSE;
1046     //          for (int32_t i = 0; i < kMaxDecimalDigits; i++) {
1047     //              int64_t digit = numberToFormat % 10;
1048     //              if (digit != 0 || doZeros) {
1049     //                  if (doZeros && useSpaces) {
1050     //                      toInsertInto.insert(_pos + getPos(), gSpace);
1051     //                  }
1052     //                  doZeros = TRUE;
1053     //                  getRuleSet()->format(digit, toInsertInto, _pos + getPos());
1054     //              }
1055     //              numberToFormat /= 10;
1056     //          }
1057
1058     DigitList dl;
1059     dl.set(number);
1060     dl.roundFixedPoint(20);     // round to 20 fraction digits.
1061     dl.reduce();                // Removes any trailing zeros.
1062     
1063     UBool pad = FALSE;
1064     for (int32_t didx = dl.getCount()-1; didx>=dl.getDecimalAt(); didx--) {
1065       // Loop iterates over fraction digits, starting with the LSD.
1066       //   include both real digits from the number, and zeros
1067       //   to the left of the MSD but to the right of the decimal point.
1068       if (pad && useSpaces) {
1069         toInsertInto.insert(_pos + getPos(), gSpace);
1070       } else {
1071         pad = TRUE;
1072       }
1073       int64_t digit = didx>=0 ? dl.getDigit(didx) - '0' : 0;
1074       getRuleSet()->format(digit, toInsertInto, _pos + getPos(), recursionCount, status);
1075     }
1076
1077     if (!pad) {
1078       // hack around lack of precision in digitlist. if we would end up with
1079       // "foo point" make sure we add a " zero" to the end.
1080       getRuleSet()->format((int64_t)0, toInsertInto, _pos + getPos(), recursionCount, status);
1081     }
1082   }
1083 }
1084
1085 //-----------------------------------------------------------------------
1086 // parsing
1087 //-----------------------------------------------------------------------
1088
1089 /**
1090  * If in "by digits" mode, parses the string as if it were a string
1091  * of individual digits; otherwise, uses the superclass function.
1092  * @param text The string to parse
1093  * @param parsePosition Ignored on entry, but updated on exit to point
1094  * to the first unmatched character
1095  * @param baseValue The partial parse result prior to entering this
1096  * function
1097  * @param upperBound Only consider rules with base values lower than
1098  * this when filling in the substitution
1099  * @param lenientParse If true, try matching the text as numerals if
1100  * matching as words doesn't work
1101  * @return If the match was successful, the current partial parse
1102  * result; otherwise new Long(0).  The result is either a Long or
1103  * a Double.
1104  */
1105
1106 UBool
1107 FractionalPartSubstitution::doParse(const UnicodeString& text,
1108                 ParsePosition& parsePosition,
1109                 double baseValue,
1110                 double /*upperBound*/,
1111                 UBool lenientParse,
1112                 Formattable& resVal) const
1113 {
1114     // if we're not in byDigits mode, we can just use the inherited
1115     // doParse()
1116     if (!byDigits) {
1117         return NFSubstitution::doParse(text, parsePosition, baseValue, 0, lenientParse, resVal);
1118
1119         // if we ARE in byDigits mode, parse the text one digit at a time
1120         // using this substitution's owning rule set (we do this by setting
1121         // upperBound to 10 when calling doParse() ) until we reach
1122         // nonmatching text
1123     } else {
1124         UnicodeString workText(text);
1125         ParsePosition workPos(1);
1126         double result = 0;
1127         int32_t digit;
1128 //          double p10 = 0.1;
1129
1130         DigitList dl;
1131         NumberFormat* fmt = NULL;
1132         while (workText.length() > 0 && workPos.getIndex() != 0) {
1133             workPos.setIndex(0);
1134             Formattable temp;
1135             getRuleSet()->parse(workText, workPos, 10, temp);
1136             UErrorCode status = U_ZERO_ERROR;
1137             digit = temp.getLong(status);
1138 //            digit = temp.getType() == Formattable::kLong ?
1139 //               temp.getLong() :
1140 //            (int32_t)temp.getDouble();
1141
1142             if (lenientParse && workPos.getIndex() == 0) {
1143                 if (!fmt) {
1144                     status = U_ZERO_ERROR;
1145                     fmt = NumberFormat::createInstance(status);
1146                     if (U_FAILURE(status)) {
1147                         delete fmt;
1148                         fmt = NULL;
1149                     }
1150                 }
1151                 if (fmt) {
1152                     fmt->parse(workText, temp, workPos);
1153                     digit = temp.getLong(status);
1154                 }
1155             }
1156
1157             if (workPos.getIndex() != 0) {
1158                 dl.append((char)('0' + digit));
1159 //                  result += digit * p10;
1160 //                  p10 /= 10;
1161                 parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex());
1162                 workText.removeBetween(0, workPos.getIndex());
1163                 while (workText.length() > 0 && workText.charAt(0) == gSpace) {
1164                     workText.removeBetween(0, 1);
1165                     parsePosition.setIndex(parsePosition.getIndex() + 1);
1166                 }
1167             }
1168         }
1169         delete fmt;
1170
1171         result = dl.getCount() == 0 ? 0 : dl.getDouble();
1172         result = composeRuleValue(result, baseValue);
1173         resVal.setDouble(result);
1174         return TRUE;
1175     }
1176 }
1177
1178 UBool
1179 FractionalPartSubstitution::operator==(const NFSubstitution& rhs) const
1180 {
1181   return NFSubstitution::operator==(rhs) &&
1182   ((const FractionalPartSubstitution*)&rhs)->byDigits == byDigits;
1183 }
1184
1185 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(FractionalPartSubstitution)
1186
1187
1188 //===================================================================
1189 // AbsoluteValueSubstitution
1190 //===================================================================
1191
1192 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(AbsoluteValueSubstitution)
1193
1194 //===================================================================
1195 // NumeratorSubstitution
1196 //===================================================================
1197
1198 void
1199 NumeratorSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t apos, int32_t recursionCount, UErrorCode& status) const {
1200     // perform a transformation on the number being formatted that
1201     // is dependent on the type of substitution this is
1202
1203     double numberToFormat = transformNumber(number);
1204     int64_t longNF = util64_fromDouble(numberToFormat);
1205
1206     const NFRuleSet* aruleSet = getRuleSet();
1207     if (withZeros && aruleSet != NULL) {
1208         // if there are leading zeros in the decimal expansion then emit them
1209         int64_t nf =longNF;
1210         int32_t len = toInsertInto.length();
1211         while ((nf *= 10) < denominator) {
1212             toInsertInto.insert(apos + getPos(), gSpace);
1213             aruleSet->format((int64_t)0, toInsertInto, apos + getPos(), recursionCount, status);
1214         }
1215         apos += toInsertInto.length() - len;
1216     }
1217
1218     // if the result is an integer, from here on out we work in integer
1219     // space (saving time and memory and preserving accuracy)
1220     if (numberToFormat == longNF && aruleSet != NULL) {
1221         aruleSet->format(longNF, toInsertInto, apos + getPos(), recursionCount, status);
1222
1223         // if the result isn't an integer, then call either our rule set's
1224         // format() method or our DecimalFormat's format() method to
1225         // format the result
1226     } else {
1227         if (aruleSet != NULL) {
1228             aruleSet->format(numberToFormat, toInsertInto, apos + getPos(), recursionCount, status);
1229         } else {
1230             UnicodeString temp;
1231             getNumberFormat()->format(numberToFormat, temp, status);
1232             toInsertInto.insert(apos + getPos(), temp);
1233         }
1234     }
1235 }
1236
1237 UBool 
1238 NumeratorSubstitution::doParse(const UnicodeString& text, 
1239                                ParsePosition& parsePosition,
1240                                double baseValue,
1241                                double upperBound,
1242                                UBool /*lenientParse*/,
1243                                Formattable& result) const
1244 {
1245     // we don't have to do anything special to do the parsing here,
1246     // but we have to turn lenient parsing off-- if we leave it on,
1247     // it SERIOUSLY messes up the algorithm
1248
1249     // if withZeros is true, we need to count the zeros
1250     // and use that to adjust the parse result
1251     UErrorCode status = U_ZERO_ERROR;
1252     int32_t zeroCount = 0;
1253     UnicodeString workText(text);
1254
1255     if (withZeros) {
1256         ParsePosition workPos(1);
1257         Formattable temp;
1258
1259         while (workText.length() > 0 && workPos.getIndex() != 0) {
1260             workPos.setIndex(0);
1261             getRuleSet()->parse(workText, workPos, 1, temp); // parse zero or nothing at all
1262             if (workPos.getIndex() == 0) {
1263                 // we failed, either there were no more zeros, or the number was formatted with digits
1264                 // either way, we're done
1265                 break;
1266             }
1267
1268             ++zeroCount;
1269             parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex());
1270             workText.remove(0, workPos.getIndex());
1271             while (workText.length() > 0 && workText.charAt(0) == gSpace) {
1272                 workText.remove(0, 1);
1273                 parsePosition.setIndex(parsePosition.getIndex() + 1);
1274             }
1275         }
1276
1277         workText = text;
1278         workText.remove(0, (int32_t)parsePosition.getIndex());
1279         parsePosition.setIndex(0);
1280     }
1281
1282     // we've parsed off the zeros, now let's parse the rest from our current position
1283     NFSubstitution::doParse(workText, parsePosition, withZeros ? 1 : baseValue, upperBound, FALSE, result);
1284
1285     if (withZeros) {
1286         // any base value will do in this case.  is there a way to
1287         // force this to not bother trying all the base values?
1288
1289         // compute the 'effective' base and prescale the value down
1290         int64_t n = result.getLong(status); // force conversion!
1291         int64_t d = 1;
1292         int32_t pow = 0;
1293         while (d <= n) {
1294             d *= 10;
1295             ++pow;
1296         }
1297         // now add the zeros
1298         while (zeroCount > 0) {
1299             d *= 10;
1300             --zeroCount;
1301         }
1302         // d is now our true denominator
1303         result.setDouble((double)n/(double)d);
1304     }
1305
1306     return TRUE;
1307 }
1308
1309 UBool
1310 NumeratorSubstitution::operator==(const NFSubstitution& rhs) const
1311 {
1312     return NFSubstitution::operator==(rhs) &&
1313         denominator == ((const NumeratorSubstitution*)&rhs)->denominator;
1314 }
1315
1316 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumeratorSubstitution)
1317
1318 const UChar NumeratorSubstitution::LTLT[] = { 0x003c, 0x003c };
1319         
1320 U_NAMESPACE_END
1321
1322 /* U_HAVE_RBNF */
1323 #endif
1324