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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libjava/] [classpath/] [java/] [text/] [DecimalFormat.java] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* 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
package java.text;
39
 
40
import gnu.java.text.AttributedFormatBuffer;
41
import gnu.java.text.FormatBuffer;
42
import gnu.java.text.FormatCharacterIterator;
43
import gnu.java.text.StringFormatBuffer;
44
 
45
import java.io.IOException;
46
import java.io.ObjectInputStream;
47
import java.util.Currency;
48
import java.util.HashMap;
49
import java.util.Locale;
50
 
51
/**
52
 * @author Tom Tromey (tromey@cygnus.com)
53
 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
54
 * @date March 4, 1999
55
 */
56
/* Written using "Java Class Libraries", 2nd edition, plus online
57
 * API docs for JDK 1.2 from http://www.javasoft.com.
58
 * Status:  Believed complete and correct to 1.2.
59
 * Note however that the docs are very unclear about how format parsing
60
 * should work.  No doubt there are problems here.
61
 */
62
public class DecimalFormat extends NumberFormat
63
{
64
  // This is a helper for applyPatternWithSymbols.  It reads a prefix
65
  // or a suffix.  It can cause some side-effects.
66
  private int scanFix (String pattern, int index, FormatBuffer buf,
67
                       String patChars, DecimalFormatSymbols syms,
68
                       boolean is_suffix)
69
    {
70
    int len = pattern.length();
71
    boolean quoteStarted = false;
72
    buf.clear();
73
 
74
    boolean multiplierSet = false;
75
    while (index < len)
76
      {
77
        char c = pattern.charAt(index);
78
 
79
        if (quoteStarted)
80
          {
81
            if (c == '\'')
82
              quoteStarted = false;
83
            else
84
              buf.append(c);
85
            index++;
86
            continue;
87
          }
88
 
89
        if (c == '\'' && index + 1 < len
90
            && pattern.charAt(index + 1) == '\'')
91
          {
92
            buf.append(c);
93
            index++;
94
          }
95
        else if (c == '\'')
96
          {
97
            quoteStarted = true;
98
          }
99
        else if (c == '\u00a4')
100
          {
101
                        /* Currency interpreted later */
102
                        buf.append(c);
103
                }
104
        else if (c == syms.getPercent())
105
          {
106
            if (multiplierSet)
107
              throw new IllegalArgumentException ("multiplier already set " +
108
                                                  "- index: " + index);
109
            multiplierSet = true;
110
            multiplier = 100;
111
            buf.append(c, NumberFormat.Field.PERCENT);
112
          }
113
        else if (c == syms.getPerMill())
114
          {
115
            if (multiplierSet)
116
              throw new IllegalArgumentException ("multiplier already set " +
117
                                                  "- index: " + index);
118
            multiplierSet = true;
119
            multiplier = 1000;
120
            buf.append(c, NumberFormat.Field.PERMILLE);
121
          }
122
        else if (patChars.indexOf(c) != -1)
123
          {
124
            // This is a pattern character.
125
            break;
126
          }
127
        else
128
                {
129
                        buf.append(c);
130
                }
131
        index++;
132
      }
133
 
134
    if (quoteStarted)
135
      throw new IllegalArgumentException ("pattern is lacking a closing quote");
136
 
137
    return index;
138
  }
139
 
140
  // A helper which reads a number format.
141
  private int scanFormat (String pattern, int index, String patChars,
142
                          DecimalFormatSymbols syms, boolean is_positive)
143
  {
144
    int max = pattern.length();
145
 
146
    int countSinceGroup = 0;
147
    int zeroCount = 0;
148
    boolean saw_group = false;
149
 
150
    //
151
    // Scan integer part.
152
    //
153
    while (index < max)
154
      {
155
        char c = pattern.charAt(index);
156
 
157
        if (c == syms.getDigit())
158
          {
159
            if (zeroCount > 0)
160
              throw new IllegalArgumentException ("digit mark following " +
161
                                                  "zero - index: " + index);
162
            ++countSinceGroup;
163
          }
164
        else if (c == syms.getZeroDigit())
165
          {
166
            ++zeroCount;
167
            ++countSinceGroup;
168
          }
169
        else if (c == syms.getGroupingSeparator())
170
          {
171
            countSinceGroup = 0;
172
            saw_group = true;
173
          }
174
        else
175
          break;
176
 
177
        ++index;
178
      }
179
 
180
    // We can only side-effect when parsing the positive format.
181
    if (is_positive)
182
      {
183
        groupingUsed = saw_group;
184
        groupingSize = (byte) countSinceGroup;
185
        // Checking "zeroCount > 0" avoids 0 being formatted into "" with "#".
186
        if (zeroCount > 0)
187
          minimumIntegerDigits = zeroCount;
188
      }
189
 
190
    // Early termination.
191
    if (index == max || pattern.charAt(index) == syms.getGroupingSeparator())
192
      {
193
        if (is_positive)
194
          decimalSeparatorAlwaysShown = false;
195
        return index;
196
      }
197
 
198
    if (pattern.charAt(index) == syms.getDecimalSeparator())
199
      {
200
        ++index;
201
 
202
        //
203
        // Scan fractional part.
204
        //
205
        int hashCount = 0;
206
        zeroCount = 0;
207
        while (index < max)
208
          {
209
            char c = pattern.charAt(index);
210
            if (c == syms.getZeroDigit())
211
              {
212
                if (hashCount > 0)
213
                  throw new IllegalArgumentException ("zero mark " +
214
                                                      "following digit - index: " + index);
215
                ++zeroCount;
216
              }
217
            else if (c == syms.getDigit())
218
              {
219
                ++hashCount;
220
              }
221
            else if (c != syms.getExponential()
222
                     && c != syms.getPatternSeparator()
223
                     && c != syms.getPercent()
224
                     && c != syms.getPerMill()
225
                     && patChars.indexOf(c) != -1)
226
              throw new IllegalArgumentException ("unexpected special " +
227
                                                  "character - index: " + index);
228
            else
229
              break;
230
 
231
            ++index;
232
          }
233
 
234
        if (is_positive)
235
          {
236
            maximumFractionDigits = hashCount + zeroCount;
237
            minimumFractionDigits = zeroCount;
238
          }
239
 
240
        if (index == max)
241
          return index;
242
      }
243
 
244
    if (pattern.charAt(index) == syms.getExponential())
245
      {
246
        //
247
        // Scan exponential format.
248
        //
249
        zeroCount = 0;
250
        ++index;
251
        while (index < max)
252
          {
253
            char c = pattern.charAt(index);
254
            if (c == syms.getZeroDigit())
255
              ++zeroCount;
256
            else if (c == syms.getDigit())
257
              {
258
                if (zeroCount > 0)
259
                  throw new
260
                    IllegalArgumentException ("digit mark following zero " +
261
                                              "in exponent - index: " +
262
                                              index);
263
              }
264
            else if (patChars.indexOf(c) != -1)
265
              throw new IllegalArgumentException ("unexpected special " +
266
                                                  "character - index: " +
267
                                                  index);
268
            else
269
              break;
270
 
271
            ++index;
272
          }
273
 
274
        if (is_positive)
275
          {
276
            useExponentialNotation = true;
277
            minExponentDigits = (byte) zeroCount;
278
          }
279
 
280
        maximumIntegerDigits = groupingSize;
281
        groupingSize = 0;
282
        if (maximumIntegerDigits > minimumIntegerDigits && maximumIntegerDigits > 0)
283
          {
284
            minimumIntegerDigits = 1;
285
            exponentRound = maximumIntegerDigits;
286
          }
287
        else
288
          exponentRound = 1;
289
      }
290
 
291
    return index;
292
  }
293
 
294
  // This helper function creates a string consisting of all the
295
  // characters which can appear in a pattern and must be quoted.
296
  private String patternChars (DecimalFormatSymbols syms)
297
  {
298
    StringBuffer buf = new StringBuffer ();
299
    buf.append(syms.getDecimalSeparator());
300
    buf.append(syms.getDigit());
301
    buf.append(syms.getExponential());
302
    buf.append(syms.getGroupingSeparator());
303
    // Adding this one causes pattern application to fail.
304
    // Of course, omitting is causes toPattern to fail.
305
    // ... but we already have bugs there.  FIXME.
306
    // buf.append(syms.getMinusSign());
307
    buf.append(syms.getPatternSeparator());
308
    buf.append(syms.getPercent());
309
    buf.append(syms.getPerMill());
310
    buf.append(syms.getZeroDigit());
311
    buf.append('\u00a4');
312
    return buf.toString();
313
  }
314
 
315
  private void applyPatternWithSymbols(String pattern, DecimalFormatSymbols syms)
316
  {
317
    // Initialize to the state the parser expects.
318
    negativePrefix = "";
319
    negativeSuffix = "";
320
    positivePrefix = "";
321
    positiveSuffix = "";
322
    decimalSeparatorAlwaysShown = false;
323
    groupingSize = 0;
324
    minExponentDigits = 0;
325
    multiplier = 1;
326
    useExponentialNotation = false;
327
    groupingUsed = false;
328
    maximumFractionDigits = 0;
329
    maximumIntegerDigits = MAXIMUM_INTEGER_DIGITS;
330
    minimumFractionDigits = 0;
331
    minimumIntegerDigits = 1;
332
 
333
    AttributedFormatBuffer buf = new AttributedFormatBuffer ();
334
    String patChars = patternChars (syms);
335
 
336
    int max = pattern.length();
337
    int index = scanFix (pattern, 0, buf, patChars, syms, false);
338
    buf.sync();
339
    positivePrefix = buf.getBuffer().toString();
340
    positivePrefixRanges = buf.getRanges();
341
    positivePrefixAttrs = buf.getAttributes();
342
 
343
    index = scanFormat (pattern, index, patChars, syms, true);
344
 
345
    index = scanFix (pattern, index, buf, patChars, syms, true);
346
    buf.sync();
347
    positiveSuffix = buf.getBuffer().toString();
348
    positiveSuffixRanges = buf.getRanges();
349
    positiveSuffixAttrs = buf.getAttributes();
350
 
351
    if (index == pattern.length())
352
      {
353
        // No negative info.
354
        negativePrefix = null;
355
        negativeSuffix = null;
356
      }
357
    else
358
      {
359
        if (pattern.charAt(index) != syms.getPatternSeparator())
360
          throw new IllegalArgumentException ("separator character " +
361
                                              "expected - index: " + index);
362
 
363
        index = scanFix (pattern, index + 1, buf, patChars, syms, false);
364
        buf.sync();
365
        negativePrefix = buf.getBuffer().toString();
366
        negativePrefixRanges = buf.getRanges();
367
        negativePrefixAttrs = buf.getAttributes();
368
 
369
        // We parse the negative format for errors but we don't let
370
        // it side-effect this object.
371
        index = scanFormat (pattern, index, patChars, syms, false);
372
 
373
        index = scanFix (pattern, index, buf, patChars, syms, true);
374
        buf.sync();
375
        negativeSuffix = buf.getBuffer().toString();
376
        negativeSuffixRanges = buf.getRanges();
377
        negativeSuffixAttrs = buf.getAttributes();
378
 
379
        if (index != pattern.length())
380
          throw new IllegalArgumentException ("end of pattern expected " +
381
                                              "- index: " + index);
382
      }
383
  }
384
 
385
  public void applyLocalizedPattern (String pattern)
386
  {
387
    // JCL p. 638 claims this throws a ParseException but p. 629
388
    // contradicts this.  Empirical tests with patterns of "0,###.0"
389
    // and "#.#.#" corroborate the p. 629 statement that an
390
    // IllegalArgumentException is thrown.
391
    applyPatternWithSymbols (pattern, symbols);
392
  }
393
 
394
  public void applyPattern (String pattern)
395
  {
396
    // JCL p. 638 claims this throws a ParseException but p. 629
397
    // contradicts this.  Empirical tests with patterns of "0,###.0"
398
    // and "#.#.#" corroborate the p. 629 statement that an
399
    // IllegalArgumentException is thrown.
400
    applyPatternWithSymbols (pattern, nonLocalizedSymbols);
401
  }
402
 
403
  public Object clone ()
404
  {
405
    DecimalFormat c = (DecimalFormat) super.clone ();
406
    c.symbols = (DecimalFormatSymbols) symbols.clone ();
407
    return c;
408
  }
409
 
410
  /**
411
   * Constructs a <code>DecimalFormat</code> which uses the default
412
   * pattern and symbols.
413
   */
414
  public DecimalFormat ()
415
  {
416
    this ("#,##0.###");
417
  }
418
 
419
  /**
420
   * Constructs a <code>DecimalFormat</code> which uses the given
421
   * pattern and the default symbols for formatting and parsing.
422
   *
423
   * @param pattern the non-localized pattern to use.
424
   * @throws NullPointerException if any argument is null.
425
   * @throws IllegalArgumentException if the pattern is invalid.
426
   */
427
  public DecimalFormat (String pattern)
428
  {
429
    this (pattern, new DecimalFormatSymbols ());
430
  }
431
 
432
  /**
433
   * Constructs a <code>DecimalFormat</code> using the given pattern
434
   * and formatting symbols.  This construction method is used to give
435
   * complete control over the formatting process.
436
   *
437
   * @param pattern the non-localized pattern to use.
438
   * @param symbols the set of symbols used for parsing and formatting.
439
   * @throws NullPointerException if any argument is null.
440
   * @throws IllegalArgumentException if the pattern is invalid.
441
   */
442
  public DecimalFormat(String pattern, DecimalFormatSymbols symbols)
443
  {
444
    this.symbols = (DecimalFormatSymbols) symbols.clone();
445
    applyPattern(pattern);
446
  }
447
 
448
  private boolean equals(String s1, String s2)
449
  {
450
    if (s1 == null || s2 == null)
451
      return s1 == s2;
452
    return s1.equals(s2);
453
  }
454
 
455
  /**
456
   * Tests this instance for equality with an arbitrary object.  This method
457
   * returns <code>true</code> if:
458
   * <ul>
459
   * <li><code>obj</code> is not <code>null</code>;</li>
460
   * <li><code>obj</code> is an instance of <code>DecimalFormat</code>;</li>
461
   * <li>this instance and <code>obj</code> have the same attributes;</li>
462
   * </ul>
463
   *
464
   * @param obj  the object (<code>null</code> permitted).
465
   *
466
   * @return A boolean.
467
   */
468
  public boolean equals(Object obj)
469
  {
470
    if (! (obj instanceof DecimalFormat))
471
      return false;
472
    DecimalFormat dup = (DecimalFormat) obj;
473
    return (decimalSeparatorAlwaysShown == dup.decimalSeparatorAlwaysShown
474
           && groupingUsed == dup.groupingUsed
475
           && groupingSize == dup.groupingSize
476
           && multiplier == dup.multiplier
477
           && useExponentialNotation == dup.useExponentialNotation
478
           && minExponentDigits == dup.minExponentDigits
479
           && minimumIntegerDigits == dup.minimumIntegerDigits
480
           && maximumIntegerDigits == dup.maximumIntegerDigits
481
           && minimumFractionDigits == dup.minimumFractionDigits
482
           && maximumFractionDigits == dup.maximumFractionDigits
483
           && equals(negativePrefix, dup.negativePrefix)
484
           && equals(negativeSuffix, dup.negativeSuffix)
485
           && equals(positivePrefix, dup.positivePrefix)
486
           && equals(positiveSuffix, dup.positiveSuffix)
487
           && symbols.equals(dup.symbols));
488
  }
489
 
490
  private void formatInternal (double number, FormatBuffer dest,
491
                               FieldPosition fieldPos)
492
  {
493
    // A very special case.
494
    if (Double.isNaN(number))
495
      {
496
        dest.append(symbols.getNaN());
497
        if (fieldPos != null &&
498
            (fieldPos.getField() == INTEGER_FIELD ||
499
             fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
500
          {
501
            int index = dest.length();
502
            fieldPos.setBeginIndex(index - symbols.getNaN().length());
503
            fieldPos.setEndIndex(index);
504
          }
505
        return;
506
      }
507
 
508
    boolean is_neg = number < 0;
509
    if (is_neg)
510
      {
511
        if (negativePrefix != null)
512
          {
513
            dest.append(substituteCurrency(negativePrefix, number),
514
                        negativePrefixRanges, negativePrefixAttrs);
515
          }
516
        else
517
          {
518
            dest.append(symbols.getMinusSign(), NumberFormat.Field.SIGN);
519
            dest.append(substituteCurrency(positivePrefix, number),
520
                        positivePrefixRanges, positivePrefixAttrs);
521
          }
522
        number = - number;
523
      }
524
    else
525
      {
526
        dest.append(substituteCurrency(positivePrefix, number),
527
                    positivePrefixRanges, positivePrefixAttrs);
528
      }
529
    int integerBeginIndex = dest.length();
530
    int integerEndIndex = 0;
531
    int zeroStart = symbols.getZeroDigit() - '0';
532
 
533
    if (Double.isInfinite (number))
534
      {
535
        dest.append(symbols.getInfinity());
536
        integerEndIndex = dest.length();
537
      }
538
    else
539
      {
540
        number *= multiplier;
541
 
542
        // Compute exponent.
543
        long exponent = 0;
544
        double baseNumber;
545
        if (useExponentialNotation)
546
          {
547
            exponent = (long) Math.floor (Math.log(number) / Math.log(10));
548
            exponent = exponent - (exponent % exponentRound);
549
            if (minimumIntegerDigits > 0)
550
              exponent -= minimumIntegerDigits - 1;
551
            baseNumber = (number / Math.pow(10.0, exponent));
552
          }
553
        else
554
          baseNumber = number;
555
 
556
        // Round to the correct number of digits.
557
        baseNumber += 5 * Math.pow(10.0, - maximumFractionDigits - 1);
558
 
559
        int index = dest.length();
560
        //double intPart = Math.floor(baseNumber);
561
        String intPart = Long.toString((long)Math.floor(baseNumber));
562
        int count, groupPosition = intPart.length();
563
 
564
        dest.setDefaultAttribute(NumberFormat.Field.INTEGER);
565
 
566
        for (count = 0; count < minimumIntegerDigits-intPart.length(); count++)
567
          dest.append(symbols.getZeroDigit());
568
 
569
        for (count = 0;
570
             count < maximumIntegerDigits && count < intPart.length();
571
             count++)
572
          {
573
            int dig = intPart.charAt(count);
574
 
575
            // Append group separator if required.
576
            if (groupingUsed && count > 0 && groupingSize != 0 && groupPosition % groupingSize == 0)
577
              {
578
                dest.append(symbols.getGroupingSeparator(), NumberFormat.Field.GROUPING_SEPARATOR);
579
                dest.setDefaultAttribute(NumberFormat.Field.INTEGER);
580
              }
581
            dest.append((char) (zeroStart + dig));
582
 
583
            groupPosition--;
584
          }
585
        dest.setDefaultAttribute(null);
586
 
587
        integerEndIndex = dest.length();
588
 
589
        int decimal_index = integerEndIndex;
590
        int consecutive_zeros = 0;
591
        int total_digits = 0;
592
 
593
        int localMaximumFractionDigits = maximumFractionDigits;
594
 
595
        if (useExponentialNotation)
596
          localMaximumFractionDigits += minimumIntegerDigits - count;
597
 
598
        // Strip integer part from NUMBER.
599
        double fracPart = baseNumber - Math.floor(baseNumber);
600
 
601
        if ( ((fracPart != 0 || minimumFractionDigits > 0) && localMaximumFractionDigits > 0)
602
             || decimalSeparatorAlwaysShown)
603
          {
604
            dest.append (symbols.getDecimalSeparator(), NumberFormat.Field.DECIMAL_SEPARATOR);
605
          }
606
 
607
        int fraction_begin = dest.length();
608
        dest.setDefaultAttribute(NumberFormat.Field.FRACTION);
609
        for (count = 0;
610
             count < localMaximumFractionDigits
611
               && (fracPart != 0 || count < minimumFractionDigits);
612
             ++count)
613
          {
614
            ++total_digits;
615
            fracPart *= 10;
616
            long dig = (long) fracPart;
617
            if (dig == 0)
618
              ++consecutive_zeros;
619
            else
620
              consecutive_zeros = 0;
621
            dest.append((char) (symbols.getZeroDigit() + dig));
622
 
623
            // Strip integer part from FRACPART.
624
            fracPart = fracPart - Math.floor (fracPart);
625
          }
626
 
627
        // Strip extraneous trailing `0's.  We can't always detect
628
        // these in the loop.
629
        int extra_zeros = Math.min (consecutive_zeros,
630
                                    total_digits - minimumFractionDigits);
631
        if (extra_zeros > 0)
632
          {
633
            dest.cutTail(extra_zeros);
634
            total_digits -= extra_zeros;
635
            if (total_digits == 0 && !decimalSeparatorAlwaysShown)
636
              dest.cutTail(1);
637
          }
638
 
639
        if (fieldPos != null && fieldPos.getField() == FRACTION_FIELD)
640
          {
641
            fieldPos.setBeginIndex(fraction_begin);
642
            fieldPos.setEndIndex(dest.length());
643
          }
644
 
645
        // Finally, print the exponent.
646
        if (useExponentialNotation)
647
          {
648
            dest.append(symbols.getExponential(), NumberFormat.Field.EXPONENT_SYMBOL);
649
            if (exponent < 0)
650
              {
651
                dest.append (symbols.getMinusSign (), NumberFormat.Field.EXPONENT_SIGN);
652
                exponent = - exponent;
653
              }
654
            index = dest.length();
655
            dest.setDefaultAttribute(NumberFormat.Field.EXPONENT);
656
            String exponentString = Long.toString ((long) exponent);
657
 
658
            for (count = 0; count < minExponentDigits-exponentString.length();
659
                 count++)
660
              dest.append((char) symbols.getZeroDigit());
661
 
662
            for (count = 0;
663
                 count < exponentString.length();
664
                 ++count)
665
              {
666
                int dig = exponentString.charAt(count);
667
                dest.append((char) (zeroStart + dig));
668
              }
669
          }
670
      }
671
 
672
    if (fieldPos != null &&
673
        (fieldPos.getField() == INTEGER_FIELD ||
674
         fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
675
      {
676
        fieldPos.setBeginIndex(integerBeginIndex);
677
        fieldPos.setEndIndex(integerEndIndex);
678
      }
679
 
680
    if (is_neg && negativeSuffix != null)
681
      {
682
        dest.append(substituteCurrency(negativeSuffix, number),
683
                    negativeSuffixRanges, negativeSuffixAttrs);
684
      }
685
    else
686
      {
687
        dest.append(substituteCurrency(positiveSuffix, number),
688
                    positiveSuffixRanges, positiveSuffixAttrs);
689
      }
690
  }
691
 
692
  public StringBuffer format (double number, StringBuffer dest,
693
                              FieldPosition fieldPos)
694
  {
695
    formatInternal (number, new StringFormatBuffer(dest), fieldPos);
696
    return dest;
697
  }
698
 
699
  public AttributedCharacterIterator formatToCharacterIterator (Object value)
700
  {
701
    AttributedFormatBuffer sbuf = new AttributedFormatBuffer();
702
 
703
    if (value instanceof Number)
704
      formatInternal(((Number) value).doubleValue(), sbuf, null);
705
    else
706
      throw new IllegalArgumentException
707
        ("Cannot format given Object as a Number");
708
 
709
    sbuf.sync();
710
    return new FormatCharacterIterator(sbuf.getBuffer().toString(),
711
                                       sbuf.getRanges(),
712
                                       sbuf.getAttributes());
713
  }
714
 
715
  public StringBuffer format (long number, StringBuffer dest,
716
                              FieldPosition fieldPos)
717
  {
718
    // If using exponential notation, we just format as a double.
719
    if (useExponentialNotation)
720
       return format ((double) number, dest, fieldPos);
721
 
722
    boolean is_neg = number < 0;
723
    if (is_neg)
724
      {
725
        if (negativePrefix != null)
726
          dest.append(substituteCurrency(negativePrefix, number));
727
        else
728
          {
729
            dest.append(symbols.getMinusSign());
730
            dest.append(substituteCurrency(positivePrefix, number));
731
          }
732
        number = - number;
733
      }
734
    else
735
      dest.append(substituteCurrency(positivePrefix, number));
736
 
737
    int integerBeginIndex = dest.length();
738
    int index = dest.length();
739
    int count = 0;
740
 
741
    /* Handle percentages, etc. */
742
    number *= multiplier;
743
    while (count < maximumIntegerDigits
744
           && (number > 0 || count < minimumIntegerDigits))
745
      {
746
        long dig = number % 10;
747
        number /= 10;
748
        // NUMBER and DIG will be less than 0 if the original number
749
        // was the most negative long.
750
        if (dig < 0)
751
          {
752
            dig = - dig;
753
            number = - number;
754
          }
755
 
756
        // Append group separator if required.
757
        if (groupingUsed && count > 0 && groupingSize != 0 && count % groupingSize == 0)
758
          dest.insert(index, symbols.getGroupingSeparator());
759
 
760
        dest.insert(index, (char) (symbols.getZeroDigit() + dig));
761
 
762
        ++count;
763
      }
764
 
765
    if (fieldPos != null && fieldPos.getField() == INTEGER_FIELD)
766
      {
767
        fieldPos.setBeginIndex(integerBeginIndex);
768
        fieldPos.setEndIndex(dest.length());
769
      }
770
 
771
    if (decimalSeparatorAlwaysShown || minimumFractionDigits > 0)
772
      {
773
        dest.append(symbols.getDecimalSeparator());
774
        if (fieldPos != null && fieldPos.getField() == FRACTION_FIELD)
775
          {
776
            fieldPos.setBeginIndex(dest.length());
777
            fieldPos.setEndIndex(dest.length() + minimumFractionDigits);
778
          }
779
      }
780
 
781
    for (count = 0; count < minimumFractionDigits; ++count)
782
      dest.append(symbols.getZeroDigit());
783
 
784
    dest.append((is_neg && negativeSuffix != null)
785
                ? substituteCurrency(negativeSuffix, number)
786
                : substituteCurrency(positiveSuffix, number));
787
    return dest;
788
  }
789
 
790
  /**
791
   * Returns the currency corresponding to the currency symbol stored
792
   * in the instance of <code>DecimalFormatSymbols</code> used by this
793
   * <code>DecimalFormat</code>.
794
   *
795
   * @return A new instance of <code>Currency</code> if
796
   * the currency code matches a known one, null otherwise.
797
   */
798
  public Currency getCurrency()
799
  {
800
    return symbols.getCurrency();
801
  }
802
 
803
  /**
804
   * Returns a copy of the symbols used by this instance.
805
   *
806
   * @return A copy of the symbols.
807
   */
808
  public DecimalFormatSymbols getDecimalFormatSymbols()
809
  {
810
    return (DecimalFormatSymbols) symbols.clone();
811
  }
812
 
813
  public int getGroupingSize ()
814
  {
815
    return groupingSize;
816
  }
817
 
818
  public int getMultiplier ()
819
  {
820
    return multiplier;
821
  }
822
 
823
  public String getNegativePrefix ()
824
  {
825
    return negativePrefix;
826
  }
827
 
828
  public String getNegativeSuffix ()
829
  {
830
    return negativeSuffix;
831
  }
832
 
833
  public String getPositivePrefix ()
834
  {
835
    return positivePrefix;
836
  }
837
 
838
  public String getPositiveSuffix ()
839
  {
840
    return positiveSuffix;
841
  }
842
 
843
  /**
844
   * Returns a hash code for this object.
845
   *
846
   * @return A hash code.
847
   */
848
  public int hashCode()
849
  {
850
    return toPattern().hashCode();
851
  }
852
 
853
  public boolean isDecimalSeparatorAlwaysShown ()
854
  {
855
    return decimalSeparatorAlwaysShown;
856
  }
857
 
858
  public Number parse (String str, ParsePosition pos)
859
  {
860
    /*
861
     * Our strategy is simple: copy the text into separate buffers: one for the int part,
862
     * one for the fraction part and for the exponential part.
863
     * We translate or omit locale-specific information.
864
     * If exponential is sufficiently big we merge the fraction and int part and
865
     * remove the '.' and then we use Long to convert the number. In the other
866
     * case, we use Double to convert the full number.
867
     */
868
 
869
    boolean is_neg = false;
870
    int index = pos.getIndex();
871
    StringBuffer int_buf = new StringBuffer ();
872
 
873
    // We have to check both prefixes, because one might be empty.  We
874
    // want to pick the longest prefix that matches.
875
    boolean got_pos = str.startsWith(positivePrefix, index);
876
    String np = (negativePrefix != null
877
                 ? negativePrefix
878
                 : positivePrefix + symbols.getMinusSign());
879
    boolean got_neg = str.startsWith(np, index);
880
 
881
    if (got_pos && got_neg)
882
      {
883
        // By checking this way, we preserve ambiguity in the case
884
        // where the negative format differs only in suffix.  We
885
        // check this again later.
886
        if (np.length() > positivePrefix.length())
887
          {
888
            is_neg = true;
889
            index += np.length();
890
          }
891
        else
892
          index += positivePrefix.length();
893
      }
894
    else if (got_neg)
895
      {
896
        is_neg = true;
897
        index += np.length();
898
      }
899
    else if (got_pos)
900
      index += positivePrefix.length();
901
    else
902
      {
903
        pos.setErrorIndex (index);
904
        return null;
905
      }
906
 
907
    // FIXME: handle Inf and NaN.
908
 
909
    // FIXME: do we have to respect minimum digits?
910
    // What about multiplier?
911
 
912
    StringBuffer buf = int_buf;
913
    StringBuffer frac_buf = null;
914
    StringBuffer exp_buf = null;
915
    int start_index = index;
916
    int max = str.length();
917
    int exp_index = -1;
918
    int last = index + maximumIntegerDigits;
919
 
920
    if (maximumFractionDigits > 0)
921
      last += maximumFractionDigits + 1;
922
 
923
    if (useExponentialNotation)
924
      last += minExponentDigits + 1;
925
 
926
    if (last > 0 && max > last)
927
      max = last;
928
 
929
    char zero = symbols.getZeroDigit();
930
    int last_group = -1;
931
    boolean int_part = true;
932
    boolean exp_part = false;
933
    for (; index < max; ++index)
934
      {
935
        char c = str.charAt(index);
936
 
937
        // FIXME: what about grouping size?
938
        if (groupingUsed && c == symbols.getGroupingSeparator())
939
          {
940
            if (last_group != -1
941
                && groupingSize != 0
942
                && (index - last_group) % groupingSize != 0)
943
              {
944
                pos.setErrorIndex(index);
945
                return null;
946
              }
947
            last_group = index+1;
948
          }
949
        else if (c >= zero && c <= zero + 9)
950
          {
951
            buf.append((char) (c - zero + '0'));
952
          }
953
        else if (parseIntegerOnly)
954
          break;
955
        else if (c == symbols.getDecimalSeparator())
956
          {
957
            if (last_group != -1
958
                && groupingSize != 0
959
                && (index - last_group) % groupingSize != 0)
960
              {
961
                pos.setErrorIndex(index);
962
                return null;
963
              }
964
            buf = frac_buf = new StringBuffer();
965
            frac_buf.append('.');
966
            int_part = false;
967
          }
968
        else if (c == symbols.getExponential())
969
          {
970
            buf = exp_buf = new StringBuffer();
971
            int_part = false;
972
            exp_part = true;
973
            exp_index = index+1;
974
          }
975
        else if (exp_part
976
                 && (c == '+' || c == '-' || c == symbols.getMinusSign()))
977
          {
978
            // For exponential notation.
979
            buf.append(c);
980
          }
981
        else
982
          break;
983
      }
984
 
985
    if (index == start_index)
986
      {
987
        // Didn't see any digits.
988
        pos.setErrorIndex(index);
989
        return null;
990
      }
991
 
992
    // Check the suffix.  We must do this before converting the
993
    // buffer to a number to handle the case of a number which is
994
    // the most negative Long.
995
    boolean got_pos_suf = str.startsWith(positiveSuffix, index);
996
    String ns = (negativePrefix == null ? positiveSuffix : negativeSuffix);
997
    boolean got_neg_suf = str.startsWith(ns, index);
998
    if (is_neg)
999
      {
1000
        if (! got_neg_suf)
1001
          {
1002
            pos.setErrorIndex(index);
1003
            return null;
1004
          }
1005
      }
1006
    else if (got_pos && got_neg && got_neg_suf)
1007
      {
1008
        is_neg = true;
1009
      }
1010
    else if (got_pos != got_pos_suf && got_neg != got_neg_suf)
1011
      {
1012
        pos.setErrorIndex(index);
1013
        return null;
1014
      }
1015
    else if (! got_pos_suf)
1016
      {
1017
       pos.setErrorIndex(index);
1018
       return null;
1019
      }
1020
 
1021
    String suffix = is_neg ? ns : positiveSuffix;
1022
    long parsedMultiplier = 1;
1023
    boolean use_long;
1024
 
1025
    if (is_neg)
1026
      int_buf.insert(0, '-');
1027
 
1028
    // Now handle the exponential part if there is one.
1029
    if (exp_buf != null)
1030
      {
1031
        int exponent_value;
1032
 
1033
        try
1034
          {
1035
            exponent_value = Integer.parseInt(exp_buf.toString());
1036
          }
1037
        catch (NumberFormatException x1)
1038
          {
1039
            pos.setErrorIndex(exp_index);
1040
            return null;
1041
          }
1042
 
1043
        if (frac_buf == null)
1044
          {
1045
            // We only have to add some zeros to the int part.
1046
            // Build a multiplier.
1047
            for (int i = 0; i < exponent_value; i++)
1048
              int_buf.append('0');
1049
 
1050
            use_long = true;
1051
          }
1052
        else
1053
          {
1054
            boolean long_sufficient;
1055
 
1056
            if (exponent_value < frac_buf.length()-1)
1057
              {
1058
                int lastNonNull = -1;
1059
                /* We have to check the fraction buffer: it may only be full of '0'
1060
                 * or be sufficiently filled with it to convert the number into Long.
1061
                 */
1062
                for (int i = 1; i < frac_buf.length(); i++)
1063
                  if (frac_buf.charAt(i) != '0')
1064
                    lastNonNull = i;
1065
 
1066
                long_sufficient = (lastNonNull < 0 || lastNonNull <= exponent_value);
1067
              }
1068
            else
1069
              long_sufficient = true;
1070
 
1071
            if (long_sufficient)
1072
              {
1073
                for (int i = 1; i < frac_buf.length() && i < exponent_value; i++)
1074
                  int_buf.append(frac_buf.charAt(i));
1075
                for (int i = frac_buf.length()-1; i < exponent_value; i++)
1076
                  int_buf.append('0');
1077
                use_long = true;
1078
              }
1079
            else
1080
              {
1081
                /*
1082
                 * A long type is not sufficient, we build the full buffer to
1083
                 * be parsed by Double.
1084
                 */
1085
                int_buf.append(frac_buf);
1086
                int_buf.append('E');
1087
                int_buf.append(exp_buf);
1088
                use_long = false;
1089
              }
1090
          }
1091
      }
1092
    else
1093
      {
1094
        if (frac_buf != null)
1095
          {
1096
            /* Check whether the fraction buffer contains only '0' */
1097
            int i;
1098
            for (i = 1; i < frac_buf.length(); i++)
1099
              if (frac_buf.charAt(i) != '0')
1100
                break;
1101
 
1102
            if (i != frac_buf.length())
1103
              {
1104
                use_long = false;
1105
                int_buf.append(frac_buf);
1106
              }
1107
            else
1108
              use_long = true;
1109
          }
1110
        else
1111
          use_long = true;
1112
      }
1113
 
1114
    String t = int_buf.toString();
1115
    Number result = null;
1116
    if (use_long)
1117
      {
1118
        try
1119
          {
1120
            result = new Long (t);
1121
          }
1122
        catch (NumberFormatException x1)
1123
          {
1124
          }
1125
      }
1126
    else
1127
      {
1128
        try
1129
          {
1130
            result = new Double (t);
1131
          }
1132
        catch (NumberFormatException x2)
1133
          {
1134
          }
1135
      }
1136
    if (result == null)
1137
      {
1138
        pos.setErrorIndex(index);
1139
        return null;
1140
      }
1141
 
1142
    pos.setIndex(index + suffix.length());
1143
 
1144
    return result;
1145
  }
1146
 
1147
  /**
1148
   * Sets the <code>Currency</code> on the
1149
   * <code>DecimalFormatSymbols</code> used, which also sets the
1150
   * currency symbols on those symbols.
1151
   */
1152
  public void setCurrency(Currency currency)
1153
  {
1154
    symbols.setCurrency(currency);
1155
  }
1156
 
1157
  /**
1158
   * Sets the symbols used by this instance.  This method makes a copy of
1159
   * the supplied symbols.
1160
   *
1161
   * @param newSymbols  the symbols (<code>null</code> not permitted).
1162
   */
1163
  public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols)
1164
  {
1165
    symbols = (DecimalFormatSymbols) newSymbols.clone();
1166
  }
1167
 
1168
  public void setDecimalSeparatorAlwaysShown (boolean newValue)
1169
  {
1170
    decimalSeparatorAlwaysShown = newValue;
1171
  }
1172
 
1173
  public void setGroupingSize (int groupSize)
1174
  {
1175
    groupingSize = (byte) groupSize;
1176
  }
1177
 
1178
  public void setMaximumFractionDigits (int newValue)
1179
  {
1180
    super.setMaximumFractionDigits(Math.min(newValue, 340));
1181
  }
1182
 
1183
  public void setMaximumIntegerDigits (int newValue)
1184
  {
1185
    super.setMaximumIntegerDigits(Math.min(newValue, 309));
1186
  }
1187
 
1188
  public void setMinimumFractionDigits (int newValue)
1189
  {
1190
    super.setMinimumFractionDigits(Math.min(newValue, 340));
1191
  }
1192
 
1193
  public void setMinimumIntegerDigits (int newValue)
1194
  {
1195
    super.setMinimumIntegerDigits(Math.min(newValue, 309));
1196
  }
1197
 
1198
  public void setMultiplier (int newValue)
1199
  {
1200
    multiplier = newValue;
1201
  }
1202
 
1203
  public void setNegativePrefix (String newValue)
1204
  {
1205
    negativePrefix = newValue;
1206
  }
1207
 
1208
  public void setNegativeSuffix (String newValue)
1209
  {
1210
    negativeSuffix = newValue;
1211
  }
1212
 
1213
  public void setPositivePrefix (String newValue)
1214
  {
1215
    positivePrefix = newValue;
1216
  }
1217
 
1218
  public void setPositiveSuffix (String newValue)
1219
  {
1220
    positiveSuffix = newValue;
1221
  }
1222
 
1223
  private void quoteFix(StringBuffer buf, String text, String patChars)
1224
  {
1225
    int len = text.length();
1226
    for (int index = 0; index < len; ++index)
1227
      {
1228
        char c = text.charAt(index);
1229
        if (patChars.indexOf(c) != -1)
1230
          {
1231
            buf.append('\'');
1232
            buf.append(c);
1233
            buf.append('\'');
1234
          }
1235
        else
1236
          buf.append(c);
1237
      }
1238
  }
1239
 
1240
  private String computePattern(DecimalFormatSymbols syms)
1241
  {
1242
    StringBuffer mainPattern = new StringBuffer ();
1243
    // We have to at least emit a zero for the minimum number of
1244
    // digits.  Past that we need hash marks up to the grouping
1245
    // separator (and one beyond).
1246
    int total_digits = Math.max(minimumIntegerDigits,
1247
                                groupingUsed ? groupingSize + 1: groupingSize);
1248
    for (int i = 0; i < total_digits - minimumIntegerDigits; ++i)
1249
      mainPattern.append(syms.getDigit());
1250
    for (int i = total_digits - minimumIntegerDigits; i < total_digits; ++i)
1251
      mainPattern.append(syms.getZeroDigit());
1252
    // Inserting the gropuing operator afterwards is easier.
1253
    if (groupingUsed)
1254
      mainPattern.insert(mainPattern.length() - groupingSize,
1255
                         syms.getGroupingSeparator());
1256
    // See if we need decimal info.
1257
    if (minimumFractionDigits > 0 || maximumFractionDigits > 0
1258
        || decimalSeparatorAlwaysShown)
1259
      mainPattern.append(syms.getDecimalSeparator());
1260
    for (int i = 0; i < minimumFractionDigits; ++i)
1261
      mainPattern.append(syms.getZeroDigit());
1262
    for (int i = minimumFractionDigits; i < maximumFractionDigits; ++i)
1263
      mainPattern.append(syms.getDigit());
1264
    if (useExponentialNotation)
1265
      {
1266
        mainPattern.append(syms.getExponential());
1267
        for (int i = 0; i < minExponentDigits; ++i)
1268
          mainPattern.append(syms.getZeroDigit());
1269
        if (minExponentDigits == 0)
1270
          mainPattern.append(syms.getDigit());
1271
      }
1272
 
1273
    String main = mainPattern.toString();
1274
    String patChars = patternChars (syms);
1275
    mainPattern.setLength(0);
1276
 
1277
    quoteFix (mainPattern, positivePrefix, patChars);
1278
    mainPattern.append(main);
1279
    quoteFix (mainPattern, positiveSuffix, patChars);
1280
 
1281
    if (negativePrefix != null)
1282
      {
1283
        quoteFix (mainPattern, negativePrefix, patChars);
1284
        mainPattern.append(main);
1285
        quoteFix (mainPattern, negativeSuffix, patChars);
1286
      }
1287
 
1288
    return mainPattern.toString();
1289
  }
1290
 
1291
  public String toLocalizedPattern ()
1292
  {
1293
    return computePattern (symbols);
1294
  }
1295
 
1296
  public String toPattern ()
1297
  {
1298
    return computePattern (nonLocalizedSymbols);
1299
  }
1300
 
1301
  private static final int MAXIMUM_INTEGER_DIGITS = 309;
1302
 
1303
  // These names are fixed by the serialization spec.
1304
  private boolean decimalSeparatorAlwaysShown;
1305
  private byte groupingSize;
1306
  private byte minExponentDigits;
1307
  private int exponentRound;
1308
  private int multiplier;
1309
  private String negativePrefix;
1310
  private String negativeSuffix;
1311
  private String positivePrefix;
1312
  private String positiveSuffix;
1313
  private int[] negativePrefixRanges, positivePrefixRanges;
1314
  private HashMap[] negativePrefixAttrs, positivePrefixAttrs;
1315
  private int[] negativeSuffixRanges, positiveSuffixRanges;
1316
  private HashMap[] negativeSuffixAttrs, positiveSuffixAttrs;
1317
  private int serialVersionOnStream = 1;
1318
  private DecimalFormatSymbols symbols;
1319
  private boolean useExponentialNotation;
1320
  private static final long serialVersionUID = 864413376551465018L;
1321
 
1322
  private void readObject(ObjectInputStream stream)
1323
    throws IOException, ClassNotFoundException
1324
  {
1325
    stream.defaultReadObject();
1326
    if (serialVersionOnStream < 1)
1327
      {
1328
        useExponentialNotation = false;
1329
        serialVersionOnStream = 1;
1330
      }
1331
  }
1332
 
1333
  // The locale-independent pattern symbols happen to be the same as
1334
  // the US symbols.
1335
  private static final DecimalFormatSymbols nonLocalizedSymbols
1336
    = new DecimalFormatSymbols (Locale.US);
1337
 
1338
  /**
1339
   * <p>
1340
   * Substitutes the currency symbol into the given string,
1341
   * based on the value used.  Currency symbols can either
1342
   * be a simple series of characters (e.g. '$'), which are
1343
   * simply used as is, or they can be of a more complex
1344
   * form:
1345
   * </p>
1346
   * <p>
1347
   * (lower bound)|(mid value)|(upper bound)
1348
   * </p>
1349
   * <p>
1350
   * where each bound has the syntax '(value)(# or <)(symbol)',
1351
   * to indicate the bounding value and the symbol used.
1352
   * </p>
1353
   * <p>
1354
   * The currency symbol replaces the currency specifier, '\u00a4',
1355
   * an unlocalised character, which thus is used as such in all formats.
1356
   * If this symbol occurs twice, the international currency code is used
1357
   * instead.
1358
   * </p>
1359
   *
1360
   * @param string The string containing the currency specifier, '\u00a4'.
1361
   * @param number the number being formatted.
1362
   * @return a string formatted for the correct currency.
1363
   */
1364
  private String substituteCurrency(String string, double number)
1365
  {
1366
    int index;
1367
    int length;
1368
    char currentChar;
1369
    StringBuffer buf;
1370
 
1371
    index = 0;
1372
    length = string.length();
1373
    buf = new StringBuffer();
1374
 
1375
    while (index < length)
1376
      {
1377
        currentChar = string.charAt(index);
1378
        if (string.charAt(index) == '\u00a4')
1379
          {
1380
            if ((index + 1) < length && string.charAt(index + 1) == '\u00a4')
1381
              {
1382
                buf.append(symbols.getInternationalCurrencySymbol());
1383
                index += 2;
1384
              }
1385
            else
1386
              {
1387
                String symbol;
1388
 
1389
                symbol = symbols.getCurrencySymbol();
1390
                if (symbol.startsWith("="))
1391
                  {
1392
                    String[] bounds;
1393
                    int[] boundValues;
1394
                    String[] boundSymbols;
1395
 
1396
                    bounds = symbol.substring(1).split("\\|");
1397
                    boundValues = new int[3];
1398
                    boundSymbols = new String[3];
1399
                    for (int a = 0; a < 3; ++a)
1400
                      {
1401
                        String[] bound;
1402
 
1403
                        bound = bounds[a].split("[#<]");
1404
                        boundValues[a] = Integer.parseInt(bound[0]);
1405
                        boundSymbols[a] = bound[1];
1406
                      }
1407
                    if (number <= boundValues[0])
1408
                      {
1409
                        buf.append(boundSymbols[0]);
1410
                      }
1411
                    else if (number >= boundValues[2])
1412
                      {
1413
                        buf.append(boundSymbols[2]);
1414
                      }
1415
                    else
1416
                      {
1417
                        buf.append(boundSymbols[1]);
1418
                      }
1419
                    ++index;
1420
                  }
1421
                else
1422
                  {
1423
                    buf.append(symbol);
1424
                    ++index;
1425
                  }
1426
              }
1427
          }
1428
        else
1429
          {
1430
            buf.append(string.charAt(index));
1431
            ++index;
1432
          }
1433
      }
1434
    return buf.toString();
1435
  }
1436
 
1437
}

powered by: WebSVN 2.1.0

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