OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [java/] [text/] [DecimalFormat.java] - Blame information for rev 771

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 771 jeremybenn
/* DecimalFormat.java -- Formats and parses numbers
2
   Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005  Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
/*
39
 * This class contains few bits from ICU4J (http://icu.sourceforge.net/),
40
 * Copyright by IBM and others and distributed under the
41
 * distributed under MIT/X.
42
 */
43
 
44
package java.text;
45
 
46
import gnu.java.lang.CPStringBuilder;
47
 
48
import java.math.BigDecimal;
49
import java.math.BigInteger;
50
 
51
import java.util.ArrayList;
52
import java.util.Currency;
53
import java.util.Locale;
54
 
55
/*
56
 * This note is here for historical reasons and because I had not the courage
57
 * to remove it :)
58
 *
59
 * @author Tom Tromey (tromey@cygnus.com)
60
 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
61
 * @date March 4, 1999
62
 *
63
 * Written using "Java Class Libraries", 2nd edition, plus online
64
 * API docs for JDK 1.2 from http://www.javasoft.com.
65
 * Status:  Believed complete and correct to 1.2.
66
 * Note however that the docs are very unclear about how format parsing
67
 * should work.  No doubt there are problems here.
68
 */
69
 
70
/**
71
 * This class is a concrete implementation of NumberFormat used to format
72
 * decimal numbers. The class can format numbers given a specific locale.
73
 * Generally, to get an instance of DecimalFormat you should call the factory
74
 * methods in the <code>NumberFormat</code> base class.
75
 *
76
 * @author Mario Torre (neugens@limasoftware.net)
77
 * @author Tom Tromey (tromey@cygnus.com)
78
 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
79
 */
80
public class DecimalFormat extends NumberFormat
81
{
82
  /** serialVersionUID for serializartion. */
83
  private static final long serialVersionUID = 864413376551465018L;
84
 
85
  /** Defines the default number of digits allowed while formatting integers. */
86
  private static final int DEFAULT_INTEGER_DIGITS = 309;
87
 
88
  /**
89
   * Defines the default number of digits allowed while formatting
90
   * fractions.
91
   */
92
  private static final int DEFAULT_FRACTION_DIGITS = 340;
93
 
94
  /**
95
   * Locale-independent pattern symbols.
96
   */
97
  // Happen to be the same as the US symbols.
98
  private static final DecimalFormatSymbols nonLocalizedSymbols
99
    = new DecimalFormatSymbols (Locale.US);
100
 
101
  /**
102
   * Defines if parse should return a BigDecimal or not.
103
   */
104
  private boolean parseBigDecimal;
105
 
106
  /**
107
   * Defines if we have to use the monetary decimal separator or
108
   * the decimal separator while formatting numbers.
109
   */
110
  private boolean useCurrencySeparator;
111
 
112
  /** Defines if the decimal separator is always shown or not. */
113
  private boolean decimalSeparatorAlwaysShown;
114
 
115
  /**
116
   * Defines if the decimal separator has to be shown.
117
   *
118
   * This is different then <code>decimalSeparatorAlwaysShown</code>,
119
   * as it defines if the format string contains a decimal separator or no.
120
   */
121
  private boolean showDecimalSeparator;
122
 
123
  /**
124
   * This field is used to determine if the grouping
125
   * separator is included in the format string or not.
126
   * This is only needed to match the behaviour of the RI.
127
   */
128
  private boolean groupingSeparatorInPattern;
129
 
130
  /** Defines the size of grouping groups when grouping is used. */
131
  private byte groupingSize;
132
 
133
  /**
134
   * This is an internal parameter used to keep track of the number
135
   * of digits the form the exponent, when exponential notation is used.
136
   * It is used with <code>exponentRound</code>
137
   */
138
  private byte minExponentDigits;
139
 
140
  /** This field is used to set the exponent in the engineering notation. */
141
  private int exponentRound;
142
 
143
  /** Multiplier used in percent style formats. */
144
  private int multiplier;
145
 
146
  /** Multiplier used in percent style formats. */
147
  private int negativePatternMultiplier;
148
 
149
  /** The negative prefix. */
150
  private String negativePrefix;
151
 
152
  /** The negative suffix. */
153
  private String negativeSuffix;
154
 
155
  /** The positive prefix. */
156
  private String positivePrefix;
157
 
158
  /** The positive suffix. */
159
  private String positiveSuffix;
160
 
161
  /** Decimal Format Symbols for the given locale. */
162
  private DecimalFormatSymbols symbols;
163
 
164
  /** Determine if we have to use exponential notation or not. */
165
  private boolean useExponentialNotation;
166
 
167
  /**
168
   * Defines the maximum number of integer digits to show when we use
169
   * the exponential notation.
170
   */
171
  private int maxIntegerDigitsExponent;
172
 
173
  /** Defines if the format string has a negative prefix or not. */
174
  private boolean hasNegativePrefix;
175
 
176
  /** Defines if the format string has a fractional pattern or not. */
177
  private boolean hasFractionalPattern;
178
 
179
  /** Stores a list of attributes for use by formatToCharacterIterator. */
180
  private ArrayList attributes = new ArrayList();
181
 
182
  /**
183
   * Constructs a <code>DecimalFormat</code> which uses the default
184
   * pattern and symbols.
185
   */
186
  public DecimalFormat()
187
  {
188
    this ("#,##0.###");
189
  }
190
 
191
  /**
192
   * Constructs a <code>DecimalFormat</code> which uses the given
193
   * pattern and the default symbols for formatting and parsing.
194
   *
195
   * @param pattern the non-localized pattern to use.
196
   * @throws NullPointerException if any argument is null.
197
   * @throws IllegalArgumentException if the pattern is invalid.
198
   */
199
  public DecimalFormat(String pattern)
200
  {
201
    this (pattern, new DecimalFormatSymbols());
202
  }
203
 
204
  /**
205
   * Constructs a <code>DecimalFormat</code> using the given pattern
206
   * and formatting symbols.  This construction method is used to give
207
   * complete control over the formatting process.
208
   *
209
   * @param pattern the non-localized pattern to use.
210
   * @param symbols the set of symbols used for parsing and formatting.
211
   * @throws NullPointerException if any argument is null.
212
   * @throws IllegalArgumentException if the pattern is invalid.
213
   */
214
  public DecimalFormat(String pattern, DecimalFormatSymbols symbols)
215
  {
216
    this.symbols = (DecimalFormatSymbols) symbols.clone();
217
    applyPatternWithSymbols(pattern, nonLocalizedSymbols);
218
  }
219
 
220
  /**
221
   * Apply the given localized patern to the current DecimalFormat object.
222
   *
223
   * @param pattern The localized pattern to apply.
224
   * @throws IllegalArgumentException if the given pattern is invalid.
225
   * @throws NullPointerException if the input pattern is null.
226
   */
227
  public void applyLocalizedPattern (String pattern)
228
  {
229
    applyPatternWithSymbols(pattern, this.symbols);
230
  }
231
 
232
  /**
233
   * Apply the given localized pattern to the current DecimalFormat object.
234
   *
235
   * @param pattern The localized pattern to apply.
236
   * @throws IllegalArgumentException if the given pattern is invalid.
237
   * @throws NullPointerException if the input pattern is null.
238
   */
239
  public void applyPattern(String pattern)
240
  {
241
    applyPatternWithSymbols(pattern, nonLocalizedSymbols);
242
  }
243
 
244
  public Object clone()
245
  {
246
    DecimalFormat c = (DecimalFormat) super.clone();
247
    c.symbols = (DecimalFormatSymbols) symbols.clone();
248
    return c;
249
  }
250
 
251
  /**
252
   * Tests this instance for equality with an arbitrary object.  This method
253
   * returns <code>true</code> if:
254
   * <ul>
255
   * <li><code>obj</code> is not <code>null</code>;</li>
256
   * <li><code>obj</code> is an instance of <code>DecimalFormat</code>;</li>
257
   * <li>this instance and <code>obj</code> have the same attributes;</li>
258
   * </ul>
259
   *
260
   * @param obj  the object (<code>null</code> permitted).
261
   *
262
   * @return A boolean.
263
   */
264
  public boolean equals(Object obj)
265
  {
266
    if (! (obj instanceof DecimalFormat))
267
      return false;
268
    DecimalFormat dup = (DecimalFormat) obj;
269
    return (decimalSeparatorAlwaysShown == dup.decimalSeparatorAlwaysShown
270
           && groupingUsed == dup.groupingUsed
271
           && groupingSeparatorInPattern == dup.groupingSeparatorInPattern
272
           && groupingSize == dup.groupingSize
273
           && multiplier == dup.multiplier
274
           && useExponentialNotation == dup.useExponentialNotation
275
           && minExponentDigits == dup.minExponentDigits
276
           && minimumIntegerDigits == dup.minimumIntegerDigits
277
           && maximumIntegerDigits == dup.maximumIntegerDigits
278
           && minimumFractionDigits == dup.minimumFractionDigits
279
           && maximumFractionDigits == dup.maximumFractionDigits
280
           && parseBigDecimal == dup.parseBigDecimal
281
           && useCurrencySeparator == dup.useCurrencySeparator
282
           && showDecimalSeparator == dup.showDecimalSeparator
283
           && exponentRound == dup.exponentRound
284
           && negativePatternMultiplier == dup.negativePatternMultiplier
285
           && maxIntegerDigitsExponent == dup.maxIntegerDigitsExponent
286
           // XXX: causes equivalent patterns to fail
287
           // && hasNegativePrefix == dup.hasNegativePrefix
288
           && equals(negativePrefix, dup.negativePrefix)
289
           && equals(negativeSuffix, dup.negativeSuffix)
290
           && equals(positivePrefix, dup.positivePrefix)
291
           && equals(positiveSuffix, dup.positiveSuffix)
292
           && symbols.equals(dup.symbols));
293
  }
294
 
295
  /**
296
   * Returns a hash code for this object.
297
   *
298
   * @return A hash code.
299
   */
300
  public int hashCode()
301
  {
302
    return toPattern().hashCode();
303
  }
304
 
305
  /**
306
   * Produce a formatted {@link String} representation of this object.
307
   * The passed object must be of type number.
308
   *
309
   * @param obj The {@link Number} to format.
310
   * @param sbuf The destination String; text will be appended to this String.
311
   * @param pos If used on input can be used to define an alignment
312
   * field. If used on output defines the offsets of the alignment field.
313
   * @return The String representation of this long.
314
   */
315
  public final StringBuffer format(Object obj, StringBuffer sbuf, FieldPosition pos)
316
  {
317
    if (obj instanceof BigInteger)
318
      {
319
        BigDecimal decimal = new BigDecimal((BigInteger) obj);
320
        formatInternal(decimal, true, sbuf, pos);
321
        return sbuf;
322
      }
323
    else if (obj instanceof BigDecimal)
324
      {
325
        formatInternal((BigDecimal) obj, true, sbuf, pos);
326
        return sbuf;
327
      }
328
 
329
    return super.format(obj, sbuf, pos);
330
  }
331
 
332
  /**
333
   * Produce a formatted {@link String} representation of this double.
334
   *
335
   * @param number The double to format.
336
   * @param dest The destination String; text will be appended to this String.
337
   * @param fieldPos If used on input can be used to define an alignment
338
   * field. If used on output defines the offsets of the alignment field.
339
   * @return The String representation of this long.
340
   * @throws NullPointerException if <code>dest</code> or fieldPos are null
341
   */
342
  public StringBuffer format(double number, StringBuffer dest,
343
                             FieldPosition fieldPos)
344
  {
345
    // special cases for double: NaN and negative or positive infinity
346
    if (Double.isNaN(number))
347
      {
348
        // 1. NaN
349
        String nan = symbols.getNaN();
350
        dest.append(nan);
351
 
352
        // update field position if required
353
        if ((fieldPos.getField() == INTEGER_FIELD ||
354
             fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
355
          {
356
            int index = dest.length();
357
            fieldPos.setBeginIndex(index - nan.length());
358
            fieldPos.setEndIndex(index);
359
          }
360
      }
361
    else if (Double.isInfinite(number))
362
      {
363
        // 2. Infinity
364
        if (number < 0)
365
          dest.append(this.negativePrefix);
366
        else
367
          dest.append(this.positivePrefix);
368
 
369
        dest.append(symbols.getInfinity());
370
 
371
        if (number < 0)
372
          dest.append(this.negativeSuffix);
373
        else
374
          dest.append(this.positiveSuffix);
375
 
376
        if ((fieldPos.getField() == INTEGER_FIELD ||
377
            fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
378
         {
379
           fieldPos.setBeginIndex(dest.length());
380
           fieldPos.setEndIndex(0);
381
         }
382
      }
383
    else
384
      {
385
        // get the number as a BigDecimal
386
        BigDecimal bigDecimal = new BigDecimal(String.valueOf(number));
387
        formatInternal(bigDecimal, false, dest, fieldPos);
388
      }
389
 
390
    return dest;
391
  }
392
 
393
  /**
394
   * Produce a formatted {@link String} representation of this long.
395
   *
396
   * @param number The long to format.
397
   * @param dest The destination String; text will be appended to this String.
398
   * @param fieldPos If used on input can be used to define an alignment
399
   * field. If used on output defines the offsets of the alignment field.
400
   * @return The String representation of this long.
401
   */
402
  public StringBuffer format(long number, StringBuffer dest,
403
                             FieldPosition fieldPos)
404
  {
405
    BigDecimal bigDecimal = new BigDecimal(String.valueOf(number));
406
    formatInternal(bigDecimal, true, dest, fieldPos);
407
    return dest;
408
  }
409
 
410
  /**
411
   * Return an <code>AttributedCharacterIterator</code> as a result of
412
   * the formatting of the passed {@link Object}.
413
   *
414
   * @return An {@link AttributedCharacterIterator}.
415
   * @throws NullPointerException if value is <code>null</code>.
416
   * @throws IllegalArgumentException if value is not an instance of
417
   * {@link Number}.
418
   */
419
  public AttributedCharacterIterator formatToCharacterIterator(Object value)
420
  {
421
    /*
422
     * This method implementation derives directly from the
423
     * ICU4J (http://icu.sourceforge.net/) library, distributed under MIT/X.
424
     */
425
 
426
    if (value == null)
427
      throw new NullPointerException("Passed Object is null");
428
 
429
    if (!(value instanceof Number)) throw new
430
      IllegalArgumentException("Cannot format given Object as a Number");
431
 
432
    StringBuffer text = new StringBuffer();
433
    attributes.clear();
434
    super.format(value, text, new FieldPosition(0));
435
 
436
    AttributedString as = new AttributedString(text.toString());
437
 
438
    // add NumberFormat field attributes to the AttributedString
439
    for (int i = 0; i < attributes.size(); i++)
440
      {
441
        FieldPosition pos = (FieldPosition) attributes.get(i);
442
        Format.Field attribute = pos.getFieldAttribute();
443
 
444
        as.addAttribute(attribute, attribute, pos.getBeginIndex(),
445
                        pos.getEndIndex());
446
      }
447
 
448
    // return the CharacterIterator from AttributedString
449
    return as.getIterator();
450
  }
451
 
452
  /**
453
   * Returns the currency corresponding to the currency symbol stored
454
   * in the instance of <code>DecimalFormatSymbols</code> used by this
455
   * <code>DecimalFormat</code>.
456
   *
457
   * @return A new instance of <code>Currency</code> if
458
   * the currency code matches a known one, null otherwise.
459
   */
460
  public Currency getCurrency()
461
  {
462
    return symbols.getCurrency();
463
  }
464
 
465
  /**
466
   * Returns a copy of the symbols used by this instance.
467
   *
468
   * @return A copy of the symbols.
469
   */
470
  public DecimalFormatSymbols getDecimalFormatSymbols()
471
  {
472
    return (DecimalFormatSymbols) symbols.clone();
473
  }
474
 
475
  /**
476
   * Gets the interval used between a grouping separator and the next.
477
   * For example, a grouping size of 3 means that the number 1234 is
478
   * formatted as 1,234.
479
   *
480
   * The actual character used as grouping separator depends on the
481
   * locale and is defined by {@link DecimalFormatSymbols#getDecimalSeparator()}
482
   *
483
   * @return The interval used between a grouping separator and the next.
484
   */
485
  public int getGroupingSize()
486
  {
487
    return groupingSize;
488
  }
489
 
490
  /**
491
   * Gets the multiplier used in percent and similar formats.
492
   *
493
   * @return The multiplier used in percent and similar formats.
494
   */
495
  public int getMultiplier()
496
  {
497
    return multiplier;
498
  }
499
 
500
  /**
501
   * Gets the negative prefix.
502
   *
503
   * @return The negative prefix.
504
   */
505
  public String getNegativePrefix()
506
  {
507
    return negativePrefix;
508
  }
509
 
510
  /**
511
   * Gets the negative suffix.
512
   *
513
   * @return The negative suffix.
514
   */
515
  public String getNegativeSuffix()
516
  {
517
    return negativeSuffix;
518
  }
519
 
520
  /**
521
   * Gets the positive prefix.
522
   *
523
   * @return The positive prefix.
524
   */
525
  public String getPositivePrefix()
526
  {
527
    return positivePrefix;
528
  }
529
 
530
  /**
531
   * Gets the positive suffix.
532
   *
533
   * @return The positive suffix.
534
   */
535
  public String getPositiveSuffix()
536
  {
537
    return positiveSuffix;
538
  }
539
 
540
  public boolean isDecimalSeparatorAlwaysShown()
541
  {
542
    return decimalSeparatorAlwaysShown;
543
  }
544
 
545
  /**
546
   * Define if <code>parse(java.lang.String, java.text.ParsePosition)</code>
547
   * should return a {@link BigDecimal} or not.
548
   *
549
   * @param newValue
550
   */
551
  public void setParseBigDecimal(boolean newValue)
552
  {
553
    this.parseBigDecimal = newValue;
554
  }
555
 
556
  /**
557
   * Returns <code>true</code> if
558
   * <code>parse(java.lang.String, java.text.ParsePosition)</code> returns
559
   * a <code>BigDecimal</code>, <code>false</code> otherwise.
560
   * The default return value for this method is <code>false</code>.
561
   *
562
   * @return <code>true</code> if the parse method returns a {@link BigDecimal},
563
   * <code>false</code> otherwise.
564
   * @since 1.5
565
   * @see #setParseBigDecimal(boolean)
566
   */
567
  public boolean isParseBigDecimal()
568
  {
569
    return this.parseBigDecimal;
570
  }
571
 
572
  /**
573
   * This method parses the specified string into a <code>Number</code>.
574
   *
575
   * The parsing starts at <code>pos</code>, which is updated as the parser
576
   * consume characters in the passed string.
577
   * On error, the <code>Position</code> object index is not updated, while
578
   * error position is set appropriately, an <code>null</code> is returned.
579
   *
580
   * @param str The string to parse.
581
   * @param pos The desired <code>ParsePosition</code>.
582
   *
583
   * @return The parsed <code>Number</code>
584
   */
585
  public Number parse(String str, ParsePosition pos)
586
  {
587
    // a special values before anything else
588
    // NaN
589
    if (str.contains(this.symbols.getNaN()))
590
      return Double.valueOf(Double.NaN);
591
 
592
    // this will be our final number
593
    CPStringBuilder number = new CPStringBuilder();
594
 
595
    // special character
596
    char minus = symbols.getMinusSign();
597
 
598
    // starting parsing position
599
    int start = pos.getIndex();
600
 
601
    // validate the string, it have to be in the
602
    // same form as the format string or parsing will fail
603
    String _negativePrefix = (this.negativePrefix.compareTo("") == 0
604
                              ? minus + positivePrefix
605
                              : this.negativePrefix);
606
 
607
    // we check both prefixes, because one might be empty.
608
    // We want to pick the longest prefix that matches.
609
    int positiveLen = positivePrefix.length();
610
    int negativeLen = _negativePrefix.length();
611
 
612
    boolean isNegative = str.startsWith(_negativePrefix);
613
    boolean isPositive = str.startsWith(positivePrefix);
614
 
615
    if (isPositive && isNegative)
616
      {
617
        // By checking this way, we preserve ambiguity in the case
618
        // where the negative format differs only in suffix.
619
        if (negativeLen > positiveLen)
620
          {
621
            start += _negativePrefix.length();
622
            isNegative = true;
623
          }
624
        else
625
          {
626
            start += positivePrefix.length();
627
            isPositive = true;
628
            if (negativeLen < positiveLen)
629
              isNegative = false;
630
          }
631
      }
632
    else if (isNegative)
633
      {
634
        start += _negativePrefix.length();
635
        isPositive = false;
636
      }
637
    else if (isPositive)
638
      {
639
        start += positivePrefix.length();
640
        isNegative = false;
641
      }
642
    else
643
      {
644
        pos.setErrorIndex(start);
645
        return null;
646
      }
647
 
648
    // other special characters used by the parser
649
    char decimalSeparator = symbols.getDecimalSeparator();
650
    char zero = symbols.getZeroDigit();
651
    char exponent = symbols.getExponential();
652
 
653
    // stop parsing position in the string
654
    int stop = start + this.maximumIntegerDigits + maximumFractionDigits + 2;
655
 
656
    if (useExponentialNotation)
657
      stop += minExponentDigits + 1;
658
 
659
    boolean inExponent = false;
660
 
661
    // correct the size of the end parsing flag
662
    int len = str.length();
663
    if (len < stop) stop = len;
664
    char groupingSeparator = symbols.getGroupingSeparator();
665
 
666
    int i = start;
667
    while (i < stop)
668
      {
669
        char ch = str.charAt(i);
670
        i++;
671
 
672
        if (ch >= zero && ch <= (zero + 9))
673
          {
674
            number.append(ch);
675
          }
676
        else if (this.parseIntegerOnly)
677
          {
678
            i--;
679
            break;
680
          }
681
        else if (ch == decimalSeparator)
682
          {
683
            number.append('.');
684
          }
685
        else if (ch == exponent)
686
          {
687
            number.append(ch);
688
            inExponent = !inExponent;
689
          }
690
        else if ((ch == '+' || ch == '-' || ch == minus))
691
          {
692
            if (inExponent)
693
              number.append(ch);
694
            else
695
              {
696
                i--;
697
                break;
698
              }
699
          }
700
        else
701
          {
702
            if (!groupingUsed || ch != groupingSeparator)
703
              {
704
                i--;
705
                break;
706
              }
707
          }
708
      }
709
 
710
    // 2nd special case: infinity
711
    // XXX: need to be tested
712
    if (str.contains(symbols.getInfinity()))
713
      {
714
        int inf = str.indexOf(symbols.getInfinity());
715
        pos.setIndex(inf);
716
 
717
        // FIXME: ouch, this is really ugly and lazy code...
718
        if (this.parseBigDecimal)
719
          {
720
            if (isNegative)
721
              return BigDecimal.valueOf(Double.NEGATIVE_INFINITY);
722
 
723
            return BigDecimal.valueOf(Double.POSITIVE_INFINITY);
724
          }
725
 
726
        if (isNegative)
727
          return Double.valueOf(Double.NEGATIVE_INFINITY);
728
 
729
        return Double.valueOf(Double.POSITIVE_INFINITY);
730
      }
731
 
732
    // no number...
733
    if (i == start || number.length() == 0)
734
      {
735
        pos.setErrorIndex(i);
736
        return null;
737
      }
738
 
739
    // now we have to check the suffix, done here after number parsing
740
    // or the index will not be updated correctly...
741
    boolean hasNegativeSuffix = str.endsWith(this.negativeSuffix);
742
    boolean hasPositiveSuffix = str.endsWith(this.positiveSuffix);
743
    boolean positiveEqualsNegative = negativeSuffix.equals(positiveSuffix);
744
 
745
    positiveLen = positiveSuffix.length();
746
    negativeLen = negativeSuffix.length();
747
 
748
    if (isNegative && !hasNegativeSuffix)
749
      {
750
        pos.setErrorIndex(i);
751
        return null;
752
      }
753
    else if (hasNegativeSuffix &&
754
             !positiveEqualsNegative &&
755
             (negativeLen > positiveLen))
756
      {
757
        isNegative = true;
758
      }
759
    else if (!hasPositiveSuffix)
760
      {
761
        pos.setErrorIndex(i);
762
        return null;
763
      }
764
 
765
    if (isNegative) number.insert(0, '-');
766
 
767
    pos.setIndex(i);
768
 
769
    // now we handle the return type
770
    BigDecimal bigDecimal = new BigDecimal(number.toString());
771
    if (this.parseBigDecimal)
772
      return bigDecimal;
773
 
774
    // want integer?
775
    if (this.parseIntegerOnly)
776
      return Long.valueOf(bigDecimal.longValue());
777
 
778
    // 3th special case -0.0
779
    if (isNegative && (bigDecimal.compareTo(BigDecimal.ZERO) == 0))
780
      return Double.valueOf(-0.0);
781
 
782
    try
783
      {
784
        BigDecimal integer
785
          = bigDecimal.setScale(0, BigDecimal.ROUND_UNNECESSARY);
786
        return Long.valueOf(integer.longValue());
787
      }
788
    catch (ArithmeticException e)
789
      {
790
        return Double.valueOf(bigDecimal.doubleValue());
791
      }
792
  }
793
 
794
  /**
795
   * Sets the <code>Currency</code> on the
796
   * <code>DecimalFormatSymbols</code> used, which also sets the
797
   * currency symbols on those symbols.
798
   *
799
   * @param currency The new <code>Currency</code> on the
800
   * <code>DecimalFormatSymbols</code>.
801
   */
802
  public void setCurrency(Currency currency)
803
  {
804
    Currency current = symbols.getCurrency();
805
    if (current != currency)
806
      {
807
        String oldSymbol = symbols.getCurrencySymbol();
808
        int len = oldSymbol.length();
809
        symbols.setCurrency(currency);
810
        String newSymbol = symbols.getCurrencySymbol();
811
        int posPre = positivePrefix.indexOf(oldSymbol);
812
        if (posPre != -1)
813
          positivePrefix = positivePrefix.substring(0, posPre) +
814
            newSymbol + positivePrefix.substring(posPre+len);
815
        int negPre = negativePrefix.indexOf(oldSymbol);
816
        if (negPre != -1)
817
          negativePrefix = negativePrefix.substring(0, negPre) +
818
            newSymbol + negativePrefix.substring(negPre+len);
819
        int posSuf = positiveSuffix.indexOf(oldSymbol);
820
        if (posSuf != -1)
821
          positiveSuffix = positiveSuffix.substring(0, posSuf) +
822
            newSymbol + positiveSuffix.substring(posSuf+len);
823
        int negSuf = negativeSuffix.indexOf(oldSymbol);
824
        if (negSuf != -1)
825
          negativeSuffix = negativeSuffix.substring(0, negSuf) +
826
            newSymbol + negativeSuffix.substring(negSuf+len);
827
      }
828
  }
829
 
830
  /**
831
   * Sets the symbols used by this instance.  This method makes a copy of
832
   * the supplied symbols.
833
   *
834
   * @param newSymbols  the symbols (<code>null</code> not permitted).
835
   */
836
  public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols)
837
  {
838
    symbols = (DecimalFormatSymbols) newSymbols.clone();
839
  }
840
 
841
  /**
842
   * Define if the decimal separator should be always visible or only
843
   * visible when needed. This method as effect only on integer values.
844
   * Pass <code>true</code> if you want the decimal separator to be
845
   * always shown, <code>false</code> otherwise.
846
   *
847
   * @param newValue true</code> if you want the decimal separator to be
848
   * always shown, <code>false</code> otherwise.
849
   */
850
  public void setDecimalSeparatorAlwaysShown(boolean newValue)
851
  {
852
    decimalSeparatorAlwaysShown = newValue;
853
  }
854
 
855
  /**
856
   * Sets the number of digits used to group portions of the integer part of
857
   * the number. For example, the number <code>123456</code>, with a grouping
858
   * size of 3, is rendered <code>123,456</code>.
859
   *
860
   * @param groupSize The number of digits used while grouping portions
861
   * of the integer part of a number.
862
   */
863
  public void setGroupingSize(int groupSize)
864
  {
865
    groupingSize = (byte) groupSize;
866
  }
867
 
868
  /**
869
   * Sets the maximum number of digits allowed in the integer
870
   * portion of a number to the specified value.
871
   * The new value will be the choosen as the minimum between
872
   * <code>newvalue</code> and 309. Any value below zero will be
873
   * replaced by zero.
874
   *
875
   * @param newValue The new maximum integer digits value.
876
   */
877
  public void setMaximumIntegerDigits(int newValue)
878
  {
879
    newValue = (newValue > 0) ? newValue : 0;
880
    super.setMaximumIntegerDigits(Math.min(newValue, DEFAULT_INTEGER_DIGITS));
881
  }
882
 
883
  /**
884
   * Sets the minimum number of digits allowed in the integer
885
   * portion of a number to the specified value.
886
   * The new value will be the choosen as the minimum between
887
   * <code>newvalue</code> and 309. Any value below zero will be
888
   * replaced by zero.
889
   *
890
   * @param newValue The new minimum integer digits value.
891
   */
892
  public void setMinimumIntegerDigits(int newValue)
893
  {
894
    newValue = (newValue > 0) ? newValue : 0;
895
    super.setMinimumIntegerDigits(Math.min(newValue,  DEFAULT_INTEGER_DIGITS));
896
  }
897
 
898
  /**
899
   * Sets the maximum number of digits allowed in the fraction
900
   * portion of a number to the specified value.
901
   * The new value will be the choosen as the minimum between
902
   * <code>newvalue</code> and 309. Any value below zero will be
903
   * replaced by zero.
904
   *
905
   * @param newValue The new maximum fraction digits value.
906
   */
907
  public void setMaximumFractionDigits(int newValue)
908
  {
909
    newValue = (newValue > 0) ? newValue : 0;
910
    super.setMaximumFractionDigits(Math.min(newValue, DEFAULT_FRACTION_DIGITS));
911
  }
912
 
913
  /**
914
   * Sets the minimum number of digits allowed in the fraction
915
   * portion of a number to the specified value.
916
   * The new value will be the choosen as the minimum between
917
   * <code>newvalue</code> and 309. Any value below zero will be
918
   * replaced by zero.
919
   *
920
   * @param newValue The new minimum fraction digits value.
921
   */
922
  public void setMinimumFractionDigits(int newValue)
923
  {
924
    newValue = (newValue > 0) ? newValue : 0;
925
    super.setMinimumFractionDigits(Math.min(newValue, DEFAULT_FRACTION_DIGITS));
926
  }
927
 
928
  /**
929
   * Sets the multiplier for use in percent and similar formats.
930
   * For example, for percent set the multiplier to 100, for permille, set the
931
   * miltiplier to 1000.
932
   *
933
   * @param newValue the new value for multiplier.
934
   */
935
  public void setMultiplier(int newValue)
936
  {
937
    multiplier = newValue;
938
  }
939
 
940
  /**
941
   * Sets the negative prefix.
942
   *
943
   * @param newValue The new negative prefix.
944
   */
945
  public void setNegativePrefix(String newValue)
946
  {
947
    negativePrefix = newValue;
948
  }
949
 
950
  /**
951
   * Sets the negative suffix.
952
   *
953
   * @param newValue The new negative suffix.
954
   */
955
  public void setNegativeSuffix(String newValue)
956
  {
957
    negativeSuffix = newValue;
958
  }
959
 
960
  /**
961
   * Sets the positive prefix.
962
   *
963
   * @param newValue The new positive prefix.
964
   */
965
  public void setPositivePrefix(String newValue)
966
  {
967
    positivePrefix = newValue;
968
  }
969
 
970
  /**
971
   * Sets the new positive suffix.
972
   *
973
   * @param newValue The new positive suffix.
974
   */
975
  public void setPositiveSuffix(String newValue)
976
  {
977
    positiveSuffix = newValue;
978
  }
979
 
980
  /**
981
   * This method returns a string with the formatting pattern being used
982
   * by this object. The string is localized.
983
   *
984
   * @return A localized <code>String</code> with the formatting pattern.
985
   * @see #toPattern()
986
   */
987
  public String toLocalizedPattern()
988
  {
989
    return computePattern(this.symbols);
990
  }
991
 
992
  /**
993
   * This method returns a string with the formatting pattern being used
994
   * by this object. The string is not localized.
995
   *
996
   * @return A <code>String</code> with the formatting pattern.
997
   * @see #toLocalizedPattern()
998
   */
999
  public String toPattern()
1000
  {
1001
    return computePattern(nonLocalizedSymbols);
1002
  }
1003
 
1004
  /* ***** private methods ***** */
1005
 
1006
  /**
1007
   * This is an shortcut helper method used to test if two given strings are
1008
   * equals.
1009
   *
1010
   * @param s1 The first string to test for equality.
1011
   * @param s2 The second string to test for equality.
1012
   * @return <code>true</code> if the strings are both <code>null</code> or
1013
   * equals.
1014
   */
1015
  private boolean equals(String s1, String s2)
1016
  {
1017
    if (s1 == null || s2 == null)
1018
      return s1 == s2;
1019
    return s1.equals(s2);
1020
  }
1021
 
1022
 
1023
  /* ****** PATTERN ****** */
1024
 
1025
  /**
1026
   * This helper function creates a string consisting of all the
1027
   * characters which can appear in a pattern and must be quoted.
1028
   */
1029
  private String patternChars (DecimalFormatSymbols syms)
1030
  {
1031
    CPStringBuilder buf = new CPStringBuilder ();
1032
 
1033
    buf.append(syms.getDecimalSeparator());
1034
    buf.append(syms.getDigit());
1035
    buf.append(syms.getExponential());
1036
    buf.append(syms.getGroupingSeparator());
1037
    buf.append(syms.getMinusSign());
1038
    buf.append(syms.getPatternSeparator());
1039
    buf.append(syms.getPercent());
1040
    buf.append(syms.getPerMill());
1041
    buf.append(syms.getZeroDigit());
1042
    buf.append('\'');
1043
    buf.append('\u00a4');
1044
 
1045
    return buf.toString();
1046
  }
1047
 
1048
  /**
1049
   * Quote special characters as defined by <code>patChars</code> in the
1050
   * input string.
1051
   *
1052
   * @param text
1053
   * @param patChars
1054
   * @return A StringBuffer with special characters quoted.
1055
   */
1056
  private CPStringBuilder quoteFix(String text, String patChars)
1057
  {
1058
    CPStringBuilder buf = new CPStringBuilder();
1059
 
1060
    int len = text.length();
1061
    char ch;
1062
    for (int index = 0; index < len; ++index)
1063
      {
1064
        ch = text.charAt(index);
1065
        if (patChars.indexOf(ch) != -1)
1066
          {
1067
            buf.append('\'');
1068
            buf.append(ch);
1069
            if (ch != '\'') buf.append('\'');
1070
          }
1071
        else
1072
          {
1073
            buf.append(ch);
1074
          }
1075
      }
1076
 
1077
    return buf;
1078
  }
1079
 
1080
  /**
1081
   * Returns the format pattern, localized to follow the given
1082
   * symbols.
1083
   */
1084
  private String computePattern(DecimalFormatSymbols symbols)
1085
  {
1086
    StringBuilder mainPattern = new StringBuilder();
1087
 
1088
    // We have to at least emit a zero for the minimum number of
1089
    // digits. Past that we need hash marks up to the grouping
1090
    // separator (and one beyond).
1091
    int _groupingSize = groupingUsed ? groupingSize + 1: groupingSize;
1092
    int totalDigits = Math.max(minimumIntegerDigits, _groupingSize);
1093
 
1094
    // if it is not in exponential notiation,
1095
    // we always have a # prebended
1096
    if (!useExponentialNotation) mainPattern.append(symbols.getDigit());
1097
 
1098
    for (int i = 1; i < totalDigits - minimumIntegerDigits; i++)
1099
      mainPattern.append(symbols.getDigit());
1100
 
1101
    for (int i = totalDigits - minimumIntegerDigits; i < totalDigits; i++)
1102
      mainPattern.append(symbols.getZeroDigit());
1103
 
1104
    if (groupingUsed)
1105
      {
1106
        mainPattern.insert(mainPattern.length() - groupingSize,
1107
                           symbols.getGroupingSeparator());
1108
      }
1109
 
1110
    // See if we need decimal info.
1111
    if (minimumFractionDigits > 0 || maximumFractionDigits > 0 ||
1112
        decimalSeparatorAlwaysShown)
1113
      {
1114
        mainPattern.append(symbols.getDecimalSeparator());
1115
      }
1116
 
1117
    for (int i = 0; i < minimumFractionDigits; ++i)
1118
      mainPattern.append(symbols.getZeroDigit());
1119
 
1120
    for (int i = minimumFractionDigits; i < maximumFractionDigits; ++i)
1121
      mainPattern.append(symbols.getDigit());
1122
 
1123
    if (useExponentialNotation)
1124
      {
1125
        mainPattern.append(symbols.getExponential());
1126
 
1127
        for (int i = 0; i < minExponentDigits; ++i)
1128
          mainPattern.append(symbols.getZeroDigit());
1129
 
1130
        if (minExponentDigits == 0)
1131
          mainPattern.append(symbols.getDigit());
1132
      }
1133
 
1134
    // save the pattern
1135
    String pattern = mainPattern.toString();
1136
 
1137
    // so far we have the pattern itself, now we need to add
1138
    // the positive and the optional negative prefixes and suffixes
1139
    String patternChars = patternChars(symbols);
1140
    mainPattern.insert(0, quoteFix(positivePrefix, patternChars));
1141
    mainPattern.append(quoteFix(positiveSuffix, patternChars));
1142
 
1143
    if (hasNegativePrefix)
1144
      {
1145
        mainPattern.append(symbols.getPatternSeparator());
1146
        mainPattern.append(quoteFix(negativePrefix, patternChars));
1147
        mainPattern.append(pattern);
1148
        mainPattern.append(quoteFix(negativeSuffix, patternChars));
1149
      }
1150
 
1151
    // finally, return the pattern string
1152
    return mainPattern.toString();
1153
  }
1154
 
1155
  /* ****** FORMAT PARSING ****** */
1156
 
1157
  /**
1158
   * Scan the input string and define a pattern suitable for use
1159
   * with this decimal format.
1160
   *
1161
   * @param pattern
1162
   * @param symbols
1163
   */
1164
  private void applyPatternWithSymbols(String pattern,
1165
                                       DecimalFormatSymbols symbols)
1166
  {
1167
    // The pattern string is described by a BNF diagram.
1168
    // we could use a recursive parser to read and prepare
1169
    // the string, but this would be too slow and resource
1170
    // intensive, while this code is quite critical as it is
1171
    // called always when the class is instantiated and every
1172
    // time a new pattern is given.
1173
    // Our strategy is to divide the string into section as given by
1174
    // the BNF diagram, iterating through the string and setting up
1175
    // the parameters we need for formatting (which is basicly what
1176
    // a descendent recursive parser would do - but without recursion).
1177
    // I'm sure that there are smarter methods to do this.
1178
 
1179
    // Restore default values. Most of these will be overwritten
1180
    // but we want to be sure that nothing is left out.
1181
    setDefaultValues();
1182
 
1183
    int len = pattern.length();
1184
    if (len == 0)
1185
      {
1186
        // this is another special case...
1187
        this.minimumIntegerDigits = 1;
1188
        this.maximumIntegerDigits = DEFAULT_INTEGER_DIGITS;
1189
        this.minimumFractionDigits = 0;
1190
        this.maximumFractionDigits = DEFAULT_FRACTION_DIGITS;
1191
 
1192
        // FIXME: ...and these values may not be valid in all locales
1193
        this.minExponentDigits = 0;
1194
        this.showDecimalSeparator = true;
1195
        this.groupingUsed = true;
1196
        this.groupingSize = 3;
1197
 
1198
        return;
1199
      }
1200
 
1201
    int start = scanFix(pattern, symbols, 0, true);
1202
    if (start < len) start = scanNumberInteger(pattern, symbols, start);
1203
    if (start < len)
1204
      {
1205
        start = scanFractionalPortion(pattern, symbols, start);
1206
      }
1207
    else
1208
      {
1209
        // special case, pattern that ends here does not have a fractional
1210
        // portion
1211
        this.minimumFractionDigits = 0;
1212
        this.maximumFractionDigits = 0;
1213
        //this.decimalSeparatorAlwaysShown = false;
1214
        //this.showDecimalSeparator = false;
1215
      }
1216
 
1217
    // XXX: this fixes a compatibility test with the RI.
1218
    // If new uses cases fail, try removing this line first.
1219
    //if (!this.hasIntegerPattern && !this.hasFractionalPattern)
1220
    //  throw new IllegalArgumentException("No valid pattern found!");
1221
 
1222
    if (start < len) start = scanExponent(pattern, symbols, start);
1223
    if (start < len) start = scanFix(pattern, symbols, start, false);
1224
    if (start < len) scanNegativePattern(pattern, symbols, start);
1225
 
1226
    if (useExponentialNotation &&
1227
        (maxIntegerDigitsExponent > minimumIntegerDigits) &&
1228
        (maxIntegerDigitsExponent > 1))
1229
      {
1230
        minimumIntegerDigits = 1;
1231
        exponentRound = maxIntegerDigitsExponent;
1232
      }
1233
 
1234
    if (useExponentialNotation)
1235
      maximumIntegerDigits = maxIntegerDigitsExponent;
1236
 
1237
    if (!this.hasFractionalPattern && this.showDecimalSeparator == true)
1238
      {
1239
        this.decimalSeparatorAlwaysShown = true;
1240
      }
1241
  }
1242
 
1243
  /**
1244
   * Scans for the prefix or suffix portion of the pattern string.
1245
   * This method handles the positive subpattern of the pattern string.
1246
   *
1247
   * @param pattern The pattern string to parse.
1248
   * @return The position in the pattern string where parsing ended.
1249
   */
1250
  private int scanFix(String pattern, DecimalFormatSymbols sourceSymbols,
1251
                      int start, boolean prefix)
1252
  {
1253
    CPStringBuilder buffer = new CPStringBuilder();
1254
 
1255
    // the number portion is always delimited by one of those
1256
    // characters
1257
    char decimalSeparator = sourceSymbols.getDecimalSeparator();
1258
    char patternSeparator = sourceSymbols.getPatternSeparator();
1259
    char groupingSeparator = sourceSymbols.getGroupingSeparator();
1260
    char digit = sourceSymbols.getDigit();
1261
    char zero = sourceSymbols.getZeroDigit();
1262
    char minus = sourceSymbols.getMinusSign();
1263
 
1264
    // other special characters, cached here to avoid method calls later
1265
    char percent = sourceSymbols.getPercent();
1266
    char permille = sourceSymbols.getPerMill();
1267
 
1268
    String currencySymbol = this.symbols.getCurrencySymbol();
1269
 
1270
    boolean quote = false;
1271
 
1272
    char ch = pattern.charAt(start);
1273
    if (ch == patternSeparator)
1274
      {
1275
        // negative subpattern
1276
        this.hasNegativePrefix = true;
1277
        ++start;
1278
        return start;
1279
      }
1280
 
1281
    int len = pattern.length();
1282
    int i;
1283
    for (i = start; i < len; i++)
1284
      {
1285
        ch = pattern.charAt(i);
1286
 
1287
        // we are entering into the negative subpattern
1288
        if (!quote && ch == patternSeparator)
1289
          {
1290
            if (this.hasNegativePrefix)
1291
              {
1292
                throw new IllegalArgumentException("Invalid pattern found: "
1293
                                                   + start);
1294
              }
1295
 
1296
            this.hasNegativePrefix = true;
1297
            ++i;
1298
            break;
1299
          }
1300
 
1301
        // this means we are inside the number portion
1302
        if (!quote &&
1303
            (ch == minus || ch == digit || ch == zero ||
1304
             ch == groupingSeparator))
1305
          break;
1306
 
1307
        if (!quote && ch == decimalSeparator)
1308
          {
1309
            this.showDecimalSeparator = true;
1310
            break;
1311
          }
1312
        else if (quote && ch != '\'')
1313
          {
1314
            buffer.append(ch);
1315
            continue;
1316
          }
1317
 
1318
        if (ch == '\u00A4')
1319
          {
1320
            // CURRENCY
1321
            currencySymbol = this.symbols.getCurrencySymbol();
1322
 
1323
            // if \u00A4 is doubled, we use the international currency symbol
1324
            if ((i + 1) < len && pattern.charAt(i + 1) == '\u00A4')
1325
              {
1326
                currencySymbol = this.symbols.getInternationalCurrencySymbol();
1327
                i++;
1328
              }
1329
 
1330
            this.useCurrencySeparator = true;
1331
            buffer.append(currencySymbol);
1332
          }
1333
        else if (ch == percent)
1334
          {
1335
            // PERCENT
1336
            this.multiplier = 100;
1337
            buffer.append(this.symbols.getPercent());
1338
          }
1339
        else if (ch == permille)
1340
          {
1341
            // PERMILLE
1342
            this.multiplier = 1000;
1343
            buffer.append(this.symbols.getPerMill());
1344
          }
1345
        else if (ch == '\'')
1346
          {
1347
            // QUOTE
1348
            if ((i + 1) < len && pattern.charAt(i + 1) == '\'')
1349
              {
1350
                // we need to add ' to the buffer
1351
                buffer.append(ch);
1352
                i++;
1353
              }
1354
            else
1355
              {
1356
                quote = !quote;
1357
                continue;
1358
              }
1359
          }
1360
        else
1361
          {
1362
            buffer.append(ch);
1363
          }
1364
      }
1365
 
1366
    if (prefix)
1367
      {
1368
        this.positivePrefix = buffer.toString();
1369
        this.negativePrefix = minus + "" + positivePrefix;
1370
      }
1371
    else
1372
      {
1373
        this.positiveSuffix = buffer.toString();
1374
      }
1375
 
1376
    return i;
1377
  }
1378
 
1379
  /**
1380
   * Scan the given string for number patterns, starting
1381
   * from <code>start</code>.
1382
   * This method searches the integer part of the pattern only.
1383
   *
1384
   * @param pattern The pattern string to parse.
1385
   * @param start The starting parse position in the string.
1386
   * @return The position in the pattern string where parsing ended,
1387
   * counted from the beginning of the string (that is, 0).
1388
   */
1389
  private int scanNumberInteger(String pattern, DecimalFormatSymbols symbols,
1390
                                int start)
1391
  {
1392
    char digit = symbols.getDigit();
1393
    char zero = symbols.getZeroDigit();
1394
    char groupingSeparator = symbols.getGroupingSeparator();
1395
    char decimalSeparator = symbols.getDecimalSeparator();
1396
    char exponent = symbols.getExponential();
1397
    char patternSeparator = symbols.getPatternSeparator();
1398
 
1399
    // count the number of zeroes in the pattern
1400
    // this number defines the minum digits in the integer portion
1401
    int zeros = 0;
1402
 
1403
    // count the number of digits used in grouping
1404
    int _groupingSize = 0;
1405
 
1406
    this.maxIntegerDigitsExponent = 0;
1407
 
1408
    boolean intPartTouched = false;
1409
 
1410
    char ch;
1411
    int len = pattern.length();
1412
    int i;
1413
    for (i = start; i < len; i++)
1414
      {
1415
        ch = pattern.charAt(i);
1416
 
1417
        // break on decimal separator or exponent or pattern separator
1418
        if (ch == decimalSeparator || ch == exponent)
1419
          break;
1420
 
1421
        if (this.hasNegativePrefix && ch == patternSeparator)
1422
          throw new IllegalArgumentException("Invalid pattern found: "
1423
                                             + start);
1424
 
1425
        if (ch == digit)
1426
          {
1427
            // in our implementation we could relax this strict
1428
            // requirement, but this is used to keep compatibility with
1429
            // the RI
1430
            if (zeros > 0) throw new
1431
              IllegalArgumentException("digit mark following zero in " +
1432
                        "positive subpattern, not allowed. Position: " + i);
1433
 
1434
            _groupingSize++;
1435
            intPartTouched = true;
1436
            this.maxIntegerDigitsExponent++;
1437
          }
1438
        else if (ch == zero)
1439
          {
1440
            zeros++;
1441
            _groupingSize++;
1442
            this.maxIntegerDigitsExponent++;
1443
          }
1444
        else if (ch == groupingSeparator)
1445
          {
1446
            this.groupingSeparatorInPattern = true;
1447
            this.groupingUsed = true;
1448
            _groupingSize = 0;
1449
          }
1450
        else
1451
          {
1452
            // any other character not listed above
1453
            // means we are in the suffix portion
1454
            break;
1455
          }
1456
      }
1457
 
1458
    if (groupingSeparatorInPattern) this.groupingSize = (byte) _groupingSize;
1459
    this.minimumIntegerDigits = zeros;
1460
 
1461
    // XXX: compatibility code with the RI: the number of minimum integer
1462
    // digits is at least one when maximumIntegerDigits is more than zero
1463
    if (intPartTouched && this.maximumIntegerDigits > 0 &&
1464
        this.minimumIntegerDigits == 0)
1465
      this.minimumIntegerDigits = 1;
1466
 
1467
    return i;
1468
  }
1469
 
1470
  /**
1471
   * Scan the given string for number patterns, starting
1472
   * from <code>start</code>.
1473
   * This method searches the fractional part of the pattern only.
1474
   *
1475
   * @param pattern The pattern string to parse.
1476
   * @param start The starting parse position in the string.
1477
   * @return The position in the pattern string where parsing ended,
1478
   * counted from the beginning of the string (that is, 0).
1479
   */
1480
  private int scanFractionalPortion(String pattern,
1481
                                    DecimalFormatSymbols symbols,
1482
                                    int start)
1483
  {
1484
    char digit = symbols.getDigit();
1485
    char zero = symbols.getZeroDigit();
1486
    char groupingSeparator = symbols.getGroupingSeparator();
1487
    char decimalSeparator = symbols.getDecimalSeparator();
1488
    char exponent = symbols.getExponential();
1489
    char patternSeparator = symbols.getPatternSeparator();
1490
 
1491
    // first character needs to be '.' otherwise we are not parsing the
1492
    // fractional portion
1493
    char ch = pattern.charAt(start);
1494
    if (ch != decimalSeparator)
1495
      {
1496
        this.minimumFractionDigits = 0;
1497
        this.maximumFractionDigits = 0;
1498
        return start;
1499
      }
1500
 
1501
    ++start;
1502
 
1503
    this.hasFractionalPattern = true;
1504
 
1505
    this.minimumFractionDigits = 0;
1506
    int digits = 0;
1507
 
1508
    int len = pattern.length();
1509
    int i;
1510
    for (i = start; i < len; i++)
1511
      {
1512
        ch = pattern.charAt(i);
1513
 
1514
        // we hit the exponential or negative subpattern
1515
        if (ch == exponent || ch == patternSeparator)
1516
          break;
1517
 
1518
        // pattern error
1519
        if (ch == groupingSeparator || ch == decimalSeparator) throw new
1520
          IllegalArgumentException("unexpected character '" + ch + "' " +
1521
                                   "in fractional subpattern. Position: " + i);
1522
 
1523
        if (ch == digit)
1524
          {
1525
            digits++;
1526
          }
1527
        else if (ch == zero)
1528
          {
1529
            if (digits > 0) throw new
1530
            IllegalArgumentException("digit mark following zero in " +
1531
                      "positive subpattern, not allowed. Position: " + i);
1532
 
1533
            this.minimumFractionDigits++;
1534
          }
1535
        else
1536
          {
1537
            // we are in the suffix section of pattern
1538
            break;
1539
          }
1540
      }
1541
 
1542
    if (i == start) this.hasFractionalPattern = false;
1543
 
1544
    this.maximumFractionDigits = this.minimumFractionDigits + digits;
1545
    this.showDecimalSeparator = true;
1546
 
1547
    return i;
1548
  }
1549
 
1550
  /**
1551
   * Scan the given string for number patterns, starting
1552
   * from <code>start</code>.
1553
   * This method searches the expoential part of the pattern only.
1554
   *
1555
   * @param pattern The pattern string to parse.
1556
   * @param start The starting parse position in the string.
1557
   * @return The position in the pattern string where parsing ended,
1558
   * counted from the beginning of the string (that is, 0).
1559
   */
1560
  private int scanExponent(String pattern, DecimalFormatSymbols symbols,
1561
                           int start)
1562
  {
1563
    char digit = symbols.getDigit();
1564
    char zero = symbols.getZeroDigit();
1565
    char groupingSeparator = symbols.getGroupingSeparator();
1566
    char decimalSeparator = symbols.getDecimalSeparator();
1567
    char exponent = symbols.getExponential();
1568
 
1569
    char ch = pattern.charAt(start);
1570
 
1571
    if (ch == decimalSeparator)
1572
      {
1573
        // ignore dots
1574
        ++start;
1575
      }
1576
 
1577
    if (ch != exponent)
1578
      {
1579
        this.useExponentialNotation = false;
1580
        return start;
1581
      }
1582
 
1583
    ++start;
1584
 
1585
    this.minExponentDigits = 0;
1586
 
1587
    int len = pattern.length();
1588
    int i;
1589
    for (i = start; i < len; i++)
1590
      {
1591
        ch = pattern.charAt(i);
1592
 
1593
        if (ch == groupingSeparator || ch == decimalSeparator ||
1594
            ch == digit || ch == exponent) throw new
1595
        IllegalArgumentException("unexpected character '" + ch + "' " +
1596
                                 "in exponential subpattern. Position: " + i);
1597
 
1598
        if (ch == zero)
1599
          {
1600
            this.minExponentDigits++;
1601
          }
1602
        else
1603
          {
1604
            // any character other than zero is an exit point
1605
            break;
1606
          }
1607
      }
1608
 
1609
    this.useExponentialNotation = true;
1610
 
1611
    return i;
1612
  }
1613
 
1614
  /**
1615
   * Scan the given string for number patterns, starting
1616
   * from <code>start</code>.
1617
   * This method searches the negative part of the pattern only and scan
1618
   * throught the end of the string.
1619
   *
1620
   * @param pattern The pattern string to parse.
1621
   * @param start The starting parse position in the string.
1622
   */
1623
  private void scanNegativePattern(String pattern,
1624
                                   DecimalFormatSymbols sourceSymbols,
1625
                                   int start)
1626
  {
1627
    StringBuilder buffer = new StringBuilder();
1628
 
1629
    // the number portion is always delimited by one of those
1630
    // characters
1631
    char decimalSeparator = sourceSymbols.getDecimalSeparator();
1632
    char patternSeparator = sourceSymbols.getPatternSeparator();
1633
    char groupingSeparator = sourceSymbols.getGroupingSeparator();
1634
    char digit = sourceSymbols.getDigit();
1635
    char zero = sourceSymbols.getZeroDigit();
1636
    char minus = sourceSymbols.getMinusSign();
1637
 
1638
    // other special charcaters, cached here to avoid method calls later
1639
    char percent = sourceSymbols.getPercent();
1640
    char permille = sourceSymbols.getPerMill();
1641
 
1642
    String CURRENCY_SYMBOL = this.symbols.getCurrencySymbol();
1643
    String currencySymbol = CURRENCY_SYMBOL;
1644
 
1645
    boolean quote = false;
1646
    boolean prefixDone = false;
1647
 
1648
    int len = pattern.length();
1649
    if (len > 0) this.hasNegativePrefix = true;
1650
 
1651
    char ch = pattern.charAt(start);
1652
    if (ch == patternSeparator)
1653
      {
1654
        // no pattern separator in the negative pattern
1655
        if ((start + 1) > len) throw new
1656
          IllegalArgumentException("unexpected character '" + ch + "' " +
1657
                                   "in negative subpattern.");
1658
        start++;
1659
      }
1660
 
1661
    int i;
1662
    for (i = start; i < len; i++)
1663
      {
1664
        ch = pattern.charAt(i);
1665
 
1666
        // this means we are inside the number portion
1667
        if (!quote &&
1668
            (ch == digit || ch == zero || ch == decimalSeparator ||
1669
             ch == patternSeparator || ch == groupingSeparator))
1670
          {
1671
            if (!prefixDone)
1672
              {
1673
                this.negativePrefix = buffer.toString();
1674
                buffer.delete(0, buffer.length());
1675
                prefixDone = true;
1676
              }
1677
          }
1678
        else if (ch == minus)
1679
          {
1680
            buffer.append(this.symbols.getMinusSign());
1681
          }
1682
        else if (quote && ch != '\'')
1683
          {
1684
            buffer.append(ch);
1685
          }
1686
        else if (ch == '\u00A4')
1687
          {
1688
            // CURRENCY
1689
            currencySymbol = CURRENCY_SYMBOL;
1690
 
1691
            // if \u00A4 is doubled, we use the international currency symbol
1692
            if ((i + 1) < len && pattern.charAt(i + 1) == '\u00A4')
1693
              {
1694
                currencySymbol = this.symbols.getInternationalCurrencySymbol();
1695
                i = i + 2;
1696
              }
1697
 
1698
            // FIXME: not sure about this, the specs says that we only have to
1699
            // change prefix and suffix, so leave it as commented
1700
            // unless in case of bug report/errors
1701
            //this.useCurrencySeparator = true;
1702
 
1703
            buffer.append(currencySymbol);
1704
          }
1705
        else if (ch == percent)
1706
          {
1707
            // PERCENT
1708
            this.negativePatternMultiplier = 100;
1709
            buffer.append(this.symbols.getPercent());
1710
          }
1711
        else if (ch == permille)
1712
          {
1713
            // PERMILLE
1714
            this.negativePatternMultiplier = 1000;
1715
            buffer.append(this.symbols.getPerMill());
1716
          }
1717
        else if (ch == '\'')
1718
          {
1719
            // QUOTE
1720
            if ((i + 1) < len && pattern.charAt(i + 1) == '\'')
1721
              {
1722
                // we need to add ' to the buffer
1723
                buffer.append(ch);
1724
                i++;
1725
              }
1726
            else
1727
              {
1728
                quote = !quote;
1729
              }
1730
          }
1731
        else if (ch == patternSeparator)
1732
          {
1733
            // no pattern separator in the negative pattern
1734
            throw new IllegalArgumentException("unexpected character '" + ch +
1735
                                               "' in negative subpattern.");
1736
          }
1737
        else
1738
          {
1739
            buffer.append(ch);
1740
          }
1741
      }
1742
 
1743
    if (prefixDone)
1744
      this.negativeSuffix = buffer.toString();
1745
    else
1746
      this.negativePrefix = buffer.toString();
1747
  }
1748
 
1749
  /* ****** FORMATTING ****** */
1750
 
1751
  /**
1752
   * Handles the real formatting.
1753
   *
1754
   * We use a BigDecimal to format the number without precision loss.
1755
   * All the rounding is done by methods in BigDecimal.
1756
   * The <code>isLong</code> parameter is used to determine if we are
1757
   * formatting a long or BigInteger. In this case, we avoid to format
1758
   * the fractional part of the number (unless specified otherwise in the
1759
   * format string) that would consist only of a 0 digit.
1760
   *
1761
   * @param number A BigDecimal representation fo the input number.
1762
   * @param dest The destination buffer.
1763
   * @param isLong A boolean that indicates if this BigDecimal is a real
1764
   * decimal or an integer.
1765
   * @param fieldPos Use to keep track of the formatting position.
1766
   */
1767
  private void formatInternal(BigDecimal number, boolean isLong,
1768
                              StringBuffer dest, FieldPosition fieldPos)
1769
  {
1770
    // The specs says that fieldPos should not be null, and that we
1771
    // should throw a NPE, but it seems that in few classes that
1772
    // reference this one, fieldPos is set to null.
1773
    // This is even defined in the javadoc, see for example MessageFormat.
1774
    // I think the best here is to check for fieldPos and build one if it is
1775
    // null. If it cause harms or regressions, just remove this line and
1776
    // fix the classes in the point of call, insted.
1777
    if (fieldPos == null) fieldPos = new FieldPosition(0);
1778
 
1779
    int _multiplier = this.multiplier;
1780
 
1781
    // used to track attribute starting position for each attribute
1782
    int attributeStart = -1;
1783
 
1784
    // now get the sign this will be used by the special case Inifinity
1785
    // and by the normal cases.
1786
    boolean isNegative = (number.signum() < 0) ? true : false;
1787
    if (isNegative)
1788
      {
1789
        attributeStart = dest.length();
1790
 
1791
        // append the negative prefix to the string
1792
        dest.append(negativePrefix);
1793
 
1794
        // once got the negative prefix, we can use
1795
        // the absolute value.
1796
        number = number.abs();
1797
 
1798
        _multiplier = negativePatternMultiplier;
1799
 
1800
        addAttribute(Field.SIGN, attributeStart, dest.length());
1801
      }
1802
    else
1803
      {
1804
        // not negative, use the positive prefix
1805
        dest.append(positivePrefix);
1806
      }
1807
 
1808
    // these are used ot update the field position
1809
    int beginIndexInt = dest.length();
1810
    int endIndexInt = 0;
1811
    int beginIndexFract = 0;
1812
    int endIndexFract = 0;
1813
 
1814
    // compute the multiplier to use with percent and similar
1815
    number = number.multiply(BigDecimal.valueOf(_multiplier));
1816
 
1817
    // XXX: special case, not sure if it belongs here or if it is
1818
    // correct at all. There may be other special cases as well
1819
    // these should be handled in the format string parser.
1820
    if (this.maximumIntegerDigits == 0 && this.maximumFractionDigits == 0)
1821
      {
1822
        number = BigDecimal.ZERO;
1823
        this.maximumIntegerDigits = 1;
1824
        this.minimumIntegerDigits = 1;
1825
      }
1826
 
1827
    //  get the absolute number
1828
    number = number.abs();
1829
 
1830
    // the scaling to use while formatting this number
1831
    int scale = this.maximumFractionDigits;
1832
 
1833
    // this is the actual number we will use
1834
    // it is corrected later on to handle exponential
1835
    // notation, if needed
1836
    long exponent = 0;
1837
 
1838
    // are we using exponential notation?
1839
    if (this.useExponentialNotation)
1840
      {
1841
        exponent = getExponent(number);
1842
        number = number.movePointLeft((int) exponent);
1843
 
1844
        // FIXME: this makes the test ##.###E0 to pass,
1845
        // but all all the other tests to fail...
1846
        // this should be really something like
1847
        // min + max - what is already shown...
1848
        //scale = this.minimumIntegerDigits + this.maximumFractionDigits;
1849
      }
1850
 
1851
    // round the number to the nearest neighbor
1852
    number = number.setScale(scale, BigDecimal.ROUND_HALF_EVEN);
1853
 
1854
    // now get the integer and fractional part of the string
1855
    // that will be processed later
1856
    String plain = number.toPlainString();
1857
 
1858
    String intPart = null;
1859
    String fractPart = null;
1860
 
1861
    // remove - from the integer part, this is needed as
1862
    // the Narrowing Primitive Conversions algorithm used may loose
1863
    // information about the sign
1864
    int minusIndex = plain.lastIndexOf('-', 0);
1865
    if (minusIndex > -1) plain = plain.substring(minusIndex + 1);
1866
 
1867
    // strip the decimal portion
1868
    int dot = plain.indexOf('.');
1869
    if (dot > -1)
1870
      {
1871
        intPart = plain.substring(0, dot);
1872
        dot++;
1873
 
1874
        if (useExponentialNotation)
1875
          fractPart = plain.substring(dot, dot + scale);
1876
        else
1877
          fractPart = plain.substring(dot);
1878
      }
1879
    else
1880
      {
1881
        intPart = plain;
1882
      }
1883
 
1884
    // used in various places later on
1885
    int intPartLen = intPart.length();
1886
    endIndexInt = intPartLen;
1887
 
1888
    // if the number of digits in our intPart is not greater than the
1889
    // minimum we have to display, we append zero to the destination
1890
    // buffer before adding the integer portion of the number.
1891
    int zeroes = minimumIntegerDigits - intPartLen;
1892
    if (zeroes > 0)
1893
      {
1894
        attributeStart = Math.max(dest.length() - 1, 0);
1895
        appendZero(dest, zeroes, minimumIntegerDigits);
1896
      }
1897
 
1898
    if (this.useExponentialNotation)
1899
      {
1900
        // For exponential numbers, the significant in mantissa are
1901
        // the sum of the minimum integer and maximum fraction
1902
        // digits, and does not take into account the maximun integer
1903
        // digits to display.
1904
 
1905
        if (attributeStart < 0)
1906
          attributeStart = Math.max(dest.length() - 1, 0);
1907
        appendDigit(intPart, dest, this.groupingUsed);
1908
      }
1909
    else
1910
      {
1911
        // non exponential notation
1912
        intPartLen = intPart.length();
1913
        int canary = Math.min(intPartLen, this.maximumIntegerDigits);
1914
 
1915
        // remove from the string the number in excess
1916
        // use only latest digits
1917
        intPart = intPart.substring(intPartLen - canary);
1918
        endIndexInt = intPart.length() + 1;
1919
 
1920
        // append it
1921
        if (maximumIntegerDigits > 0 &&
1922
            !(this.minimumIntegerDigits == 0 &&
1923
             intPart.compareTo(String.valueOf(symbols.getZeroDigit())) == 0))
1924
          {
1925
            if (attributeStart < 0)
1926
              attributeStart = Math.max(dest.length() - 1, 0);
1927
            appendDigit(intPart, dest, this.groupingUsed);
1928
          }
1929
      }
1930
 
1931
    // add the INTEGER attribute
1932
    addAttribute(Field.INTEGER, attributeStart, dest.length());
1933
 
1934
    // ...update field position, if needed, and return...
1935
    if ((fieldPos.getField() == INTEGER_FIELD ||
1936
        fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
1937
      {
1938
        fieldPos.setBeginIndex(beginIndexInt);
1939
        fieldPos.setEndIndex(endIndexInt);
1940
      }
1941
 
1942
    handleFractionalPart(dest, fractPart, fieldPos, isLong);
1943
 
1944
    // and the exponent
1945
    if (this.useExponentialNotation)
1946
      {
1947
        attributeStart = dest.length();
1948
 
1949
        dest.append(symbols.getExponential());
1950
 
1951
        addAttribute(Field.EXPONENT_SYMBOL, attributeStart, dest.length());
1952
        attributeStart = dest.length();
1953
 
1954
        if (exponent < 0)
1955
          {
1956
            dest.append(symbols.getMinusSign());
1957
            exponent = -exponent;
1958
 
1959
            addAttribute(Field.EXPONENT_SIGN, attributeStart, dest.length());
1960
          }
1961
 
1962
        attributeStart = dest.length();
1963
 
1964
        String exponentString = String.valueOf(exponent);
1965
        int exponentLength = exponentString.length();
1966
 
1967
        for (int i = 0; i < minExponentDigits - exponentLength; i++)
1968
          dest.append(symbols.getZeroDigit());
1969
 
1970
        for (int i = 0; i < exponentLength; ++i)
1971
          dest.append(exponentString.charAt(i));
1972
 
1973
        addAttribute(Field.EXPONENT, attributeStart, dest.length());
1974
      }
1975
 
1976
    // now include the suffixes...
1977
    if (isNegative)
1978
      {
1979
        dest.append(negativeSuffix);
1980
      }
1981
    else
1982
      {
1983
        dest.append(positiveSuffix);
1984
      }
1985
  }
1986
 
1987
  /**
1988
   * Add to the input buffer the result of formatting the fractional
1989
   * portion of the number.
1990
   *
1991
   * @param dest
1992
   * @param fractPart
1993
   * @param fieldPos
1994
   * @param isLong
1995
   */
1996
  private void handleFractionalPart(StringBuffer dest, String fractPart,
1997
                                    FieldPosition fieldPos, boolean isLong)
1998
  {
1999
    int dotStart = 0;
2000
    int dotEnd = 0;
2001
    boolean addDecimal = false;
2002
 
2003
    if (this.decimalSeparatorAlwaysShown  ||
2004
         ((!isLong || this.useExponentialNotation) &&
2005
           this.showDecimalSeparator && this.maximumFractionDigits > 0) ||
2006
        this.minimumFractionDigits > 0)
2007
      {
2008
        dotStart = dest.length();
2009
 
2010
        if (this.useCurrencySeparator)
2011
          dest.append(symbols.getMonetaryDecimalSeparator());
2012
        else
2013
          dest.append(symbols.getDecimalSeparator());
2014
 
2015
        dotEnd = dest.length();
2016
        addDecimal = true;
2017
      }
2018
 
2019
    // now handle the fraction portion of the number
2020
    int fractStart = 0;
2021
    int fractEnd = 0;
2022
    boolean addFractional = false;
2023
 
2024
    if ((!isLong || this.useExponentialNotation)
2025
        && this.maximumFractionDigits > 0
2026
        || this.minimumFractionDigits > 0)
2027
      {
2028
        fractStart = dest.length();
2029
        fractEnd = fractStart;
2030
 
2031
        int digits = this.minimumFractionDigits;
2032
 
2033
        if (this.useExponentialNotation)
2034
          {
2035
            digits = (this.minimumIntegerDigits + this.minimumFractionDigits)
2036
              - dest.length();
2037
            if (digits < 0) digits = 0;
2038
          }
2039
 
2040
        fractPart = adjustTrailingZeros(fractPart, digits);
2041
 
2042
        // FIXME: this code must be improved
2043
        // now check if the factional part is just 0, in this case
2044
        // we need to remove the '.' unless requested
2045
        boolean allZeros = true;
2046
        char fracts[] = fractPart.toCharArray();
2047
        for (int i = 0; i < fracts.length; i++)
2048
          {
2049
            if (fracts[i] != '0')
2050
              allZeros = false;
2051
          }
2052
 
2053
        if (!allZeros || (minimumFractionDigits > 0))
2054
          {
2055
            appendDigit(fractPart, dest, false);
2056
            fractEnd = dest.length();
2057
 
2058
            addDecimal = true;
2059
            addFractional = true;
2060
          }
2061
        else if (!this.decimalSeparatorAlwaysShown)
2062
          {
2063
            dest.deleteCharAt(dest.length() - 1);
2064
            addDecimal = false;
2065
          }
2066
        else
2067
          {
2068
            fractEnd = dest.length();
2069
            addFractional = true;
2070
          }
2071
      }
2072
 
2073
    if (addDecimal)
2074
      addAttribute(Field.DECIMAL_SEPARATOR, dotStart, dotEnd);
2075
 
2076
    if (addFractional)
2077
      addAttribute(Field.FRACTION, fractStart, fractEnd);
2078
 
2079
    if ((fieldPos.getField() == FRACTION_FIELD ||
2080
        fieldPos.getFieldAttribute() == NumberFormat.Field.FRACTION))
2081
      {
2082
        fieldPos.setBeginIndex(fractStart);
2083
        fieldPos.setEndIndex(fractEnd);
2084
      }
2085
  }
2086
 
2087
  /**
2088
   * Append to <code>dest</code>the give number of zeros.
2089
   * Grouping is added if needed.
2090
   * The integer totalDigitCount defines the total number of digits
2091
   * of the number to which we are appending zeroes.
2092
   */
2093
  private void appendZero(StringBuffer dest, int zeroes, int totalDigitCount)
2094
  {
2095
    char ch = symbols.getZeroDigit();
2096
    char gSeparator = symbols.getGroupingSeparator();
2097
 
2098
    int i = 0;
2099
    int gPos = totalDigitCount;
2100
    for (i = 0; i < zeroes; i++, gPos--)
2101
      {
2102
        if (this.groupingSeparatorInPattern &&
2103
            (this.groupingUsed && this.groupingSize != 0) &&
2104
            (gPos % groupingSize == 0 && i > 0))
2105
          dest.append(gSeparator);
2106
 
2107
        dest.append(ch);
2108
      }
2109
 
2110
    // special case, that requires adding an additional separator
2111
    if (this.groupingSeparatorInPattern &&
2112
        (this.groupingUsed && this.groupingSize != 0) &&
2113
        (gPos % groupingSize == 0))
2114
      dest.append(gSeparator);
2115
  }
2116
 
2117
  /**
2118
   * Append src to <code>dest</code>.
2119
   *
2120
   * Grouping is added if <code>groupingUsed</code> is set
2121
   * to <code>true</code>.
2122
   */
2123
  private void appendDigit(String src, StringBuffer dest,
2124
                             boolean groupingUsed)
2125
  {
2126
    int zero = symbols.getZeroDigit() - '0';
2127
 
2128
    int ch;
2129
    char gSeparator = symbols.getGroupingSeparator();
2130
 
2131
    int len = src.length();
2132
    for (int i = 0, gPos = len; i < len; i++, gPos--)
2133
      {
2134
        ch = src.charAt(i);
2135
        if (groupingUsed && this.groupingSize != 0 &&
2136
            gPos % groupingSize == 0 && i > 0)
2137
          dest.append(gSeparator);
2138
 
2139
        dest.append((char) (zero + ch));
2140
      }
2141
  }
2142
 
2143
  /**
2144
   * Calculate the exponent to use if eponential notation is used.
2145
   * The exponent is calculated as a power of ten.
2146
   * <code>number</code> should be positive, if is zero, or less than zero,
2147
   * zero is returned.
2148
   */
2149
  private long getExponent(BigDecimal number)
2150
  {
2151
    long exponent = 0;
2152
 
2153
    if (number.signum() > 0)
2154
      {
2155
        double _number = number.doubleValue();
2156
        exponent = (long) Math.floor (Math.log10(_number));
2157
 
2158
        // get the right value for the exponent
2159
        exponent = exponent - (exponent % this.exponentRound);
2160
 
2161
        // if the minimumIntegerDigits is more than zero
2162
        // we display minimumIntegerDigits of digits.
2163
        // so, for example, if minimumIntegerDigits == 2
2164
        // and the actual number is 0.123 it will be
2165
        // formatted as 12.3E-2
2166
        // this means that the exponent have to be shifted
2167
        // to the correct value.
2168
        if (minimumIntegerDigits > 0)
2169
              exponent -= minimumIntegerDigits - 1;
2170
      }
2171
 
2172
    return exponent;
2173
  }
2174
 
2175
  /**
2176
   * Remove contiguos zeros from the end of the <code>src</code> string,
2177
   * if src contains more than <code>minimumDigits</code> digits.
2178
   * if src contains less that <code>minimumDigits</code>,
2179
   * then append zeros to the string.
2180
   *
2181
   * Only the first block of zero digits is removed from the string
2182
   * and only if they fall in the src.length - minimumDigits
2183
   * portion of the string.
2184
   *
2185
   * @param src The string with the correct number of zeros.
2186
   */
2187
  private String adjustTrailingZeros(String src, int minimumDigits)
2188
  {
2189
    int len = src.length();
2190
    String result;
2191
 
2192
    // remove all trailing zero
2193
    if (len > minimumDigits)
2194
      {
2195
        int zeros = 0;
2196
        for (int i = len - 1; i > minimumDigits; i--)
2197
          {
2198
            if (src.charAt(i) == '0')
2199
              ++zeros;
2200
            else
2201
              break;
2202
          }
2203
        result =  src.substring(0, len - zeros);
2204
      }
2205
    else
2206
      {
2207
        char zero = symbols.getZeroDigit();
2208
        CPStringBuilder _result = new CPStringBuilder(src);
2209
        for (int i = len; i < minimumDigits; i++)
2210
          {
2211
            _result.append(zero);
2212
          }
2213
        result = _result.toString();
2214
      }
2215
 
2216
    return result;
2217
  }
2218
 
2219
  /**
2220
   * Adds an attribute to the attributes list.
2221
   *
2222
   * @param field
2223
   * @param begin
2224
   * @param end
2225
   */
2226
  private void addAttribute(Field field, int begin, int end)
2227
  {
2228
    /*
2229
     * This method and its implementation derives directly from the
2230
     * ICU4J (http://icu.sourceforge.net/) library, distributed under MIT/X.
2231
     */
2232
 
2233
    FieldPosition pos = new FieldPosition(field);
2234
    pos.setBeginIndex(begin);
2235
    pos.setEndIndex(end);
2236
    attributes.add(pos);
2237
  }
2238
 
2239
  /**
2240
   * Sets the default values for the various properties in this DecimaFormat.
2241
   */
2242
  private void setDefaultValues()
2243
  {
2244
    // Maybe we should add these values to the message bundle and take
2245
    // the most appropriate for them for any locale.
2246
    // Anyway, these seem to be good values for a default in most languages.
2247
    // Note that most of these will change based on the format string.
2248
 
2249
    this.negativePrefix = String.valueOf(symbols.getMinusSign());
2250
    this.negativeSuffix = "";
2251
    this.positivePrefix = "";
2252
    this.positiveSuffix = "";
2253
 
2254
    this.multiplier = 1;
2255
    this.negativePatternMultiplier = 1;
2256
    this.exponentRound = 1;
2257
 
2258
    this.hasNegativePrefix = false;
2259
 
2260
    this.minimumIntegerDigits = 1;
2261
    this.maximumIntegerDigits = DEFAULT_INTEGER_DIGITS;
2262
    this.minimumFractionDigits = 0;
2263
    this.maximumFractionDigits = DEFAULT_FRACTION_DIGITS;
2264
    this.minExponentDigits = 0;
2265
 
2266
    this.groupingSize = 0;
2267
 
2268
    this.decimalSeparatorAlwaysShown = false;
2269
    this.showDecimalSeparator = false;
2270
    this.useExponentialNotation = false;
2271
    this.groupingUsed = false;
2272
    this.groupingSeparatorInPattern = false;
2273
 
2274
    this.useCurrencySeparator = false;
2275
 
2276
    this.hasFractionalPattern = false;
2277
  }
2278
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.