001    /*
002    // $Id: //open/mondrian/src/main/mondrian/util/Format.java#30 $
003    // This software is subject to the terms of the Common Public License
004    // Agreement, available at the following URL:
005    // http://www.opensource.org/licenses/cpl.html.
006    // Copyright (C) 2000-2002 Kana Software, Inc.
007    // Copyright (C) 2001-2008 Julian Hyde and others
008    // All Rights Reserved.
009    // You must accept the terms of that agreement to use this software.
010    //
011    // jhyde, 2 November, 2000
012    */
013    
014    package mondrian.util;
015    import mondrian.olap.Util;
016    
017    import java.io.PrintWriter;
018    import java.math.BigDecimal;
019    import java.math.BigInteger;
020    import java.text.*;
021    import java.util.*;
022    
023    /**
024     * <code>Format</code> formats numbers, strings and dates according to the
025     * same specification as Visual Basic's
026     * <code>format()</code> function.  This function is described in more detail
027     * <a href="http://www.apostate.com/programming/vb-format.html">here</a>.  We
028     * have made the following enhancements to this specification:<ul>
029     *
030     * <li>if the international currency symbol (&#x00a4;) occurs in a format
031     *   string, it is translated to the locale's currency symbol.</li>
032     *
033     * <li>the format string "Currency" is translated to the locale's currency
034     *   format string. Negative currency values appear in parentheses.</li>
035     *
036     * <li>the string "USD" (abbreviation for U.S. Dollars) may occur in a format
037     *   string.</li>
038     *
039     * </ul>
040     *
041     * <p>One format object can be used to format multiple values, thereby
042     * amortizing the time required to parse the format string.  Example:</p>
043     *
044     * <pre><code>
045     * double[] values;
046     * Format format = new Format("##,##0.###;(##,##0.###);;Nil");
047     * for (int i = 0; i < values.length; i++) {
048     *   System.out.println("Value #" + i + " is " + format.format(values[i]));
049     * }
050     * </code></pre>
051     *
052     * <p>Still to be implemented:<ul>
053     *
054     * <li>String formatting (upper-case, lower-case, fill from left/right)</li>
055     *
056     * <li>Use client's timezone for printing times.</li>
057     *
058     * </ul>
059     *
060     * @author jhyde
061     * @version $Id: //open/mondrian/src/main/mondrian/util/Format.java#30 $
062     */
063    public class Format {
064        private String formatString;
065        private BasicFormat format;
066        private FormatLocale locale;
067        private static final FieldPosition dummyFieldPos = createDummyFieldPos();
068    
069        /**
070         * Maximum number of entries in the format cache used by
071         * {@link #get(String, java.util.Locale)}.
072         */
073        public static final int CacheLimit = 1000;
074    
075        /**
076         * Gets the dummy implementation of {@link FieldPosition} which the JDK
077         * uses when you don't care about the status of a call to
078         * {@link Format#format}.
079         */
080        private static FieldPosition createDummyFieldPos() {
081            final DummyDecimalFormat format1 = new DummyDecimalFormat();
082            format1.format(0.0);
083            return format1.pos;
084        }
085    
086        /**
087         * Maps (formatString, locale) pairs to {@link Format} objects.
088         *
089         * <p>If the number of entries in the cache exceeds 1000,
090         */
091        private static Map<String, Format> cache =
092            new LinkedHashMap<String, Format>() {
093                public boolean removeEldestEntry(Map.Entry<String, Format> entry) {
094                    return size() > CacheLimit;
095                }
096            };
097    
098        static final char[] digits = {
099            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
100        };
101    
102        static final char thousandSeparator_en = ',';
103        static final char decimalPlaceholder_en = '.';
104        static final String dateSeparator_en = "/";
105        static final String timeSeparator_en = ":";
106        static final String currencySymbol_en = "$";
107        static final String currencyFormat_en = "$#,##0.00";
108        static final String[] daysOfWeekShort_en = {
109            "", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
110        };
111        static final String[] daysOfWeekLong_en = {
112            "", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
113            "Saturday"
114        };
115        static final String[] monthsShort_en = {
116            "Jan", "Feb", "Mar", "Apr", "May", "Jun",
117            "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "",
118        };
119        static final String[] monthsLong_en = {
120            "January", "February", "March", "April", "May", "June",
121            "July", "August", "September", "October", "November", "December", "",
122        };
123        static final char intlCurrencySymbol = '\u08a4';
124    
125        /**
126         * Maps strings representing locales (for example, "en_US_Boston", "en_US",
127         * "en", or "" for the default) to a {@link Format.FormatLocale}.
128         */
129        private static final Map<String, FormatLocale> mapLocaleToFormatLocale =
130            new HashMap<String, FormatLocale>();
131    
132        /**
133         * Locale for US English, also the default for English and for all
134         * locales.
135         */
136        static final FormatLocale locale_US = createLocale(
137            '\0', '\0', null, null, null, null, null, null, null, null,
138            Locale.US);
139    
140        /**
141         * Formats an object using a format string, according to a given locale.
142         *
143         * <p>If you need to format many objects using the same format string,
144         * create a formatter object using
145         * {@link mondrian.util.Format#Format(String, java.util.Locale)}.
146         */
147        static String format(Object o, String formatString, Locale locale)
148        {
149            Format format = new Format(formatString, locale);
150            return format.format(o);
151        }
152    
153        static class Token {
154            int code;
155            int flags;
156            String token;
157    
158            Token(int code, int flags, String token)
159            {
160                this.code = code;
161                this.flags = flags;
162                this.token = token;
163            }
164    
165            boolean isSpecial()
166            {
167                return (flags & SPECIAL) == SPECIAL;
168            }
169    
170            boolean isNumeric()
171            {
172                return (flags & NUMERIC) == NUMERIC;
173            }
174    
175            boolean isDate()
176            {
177                return (flags & DATE) == DATE;
178            }
179    
180            boolean isString()
181            {
182                return (flags & STRING) == STRING;
183            }
184    
185            BasicFormat makeFormat(FormatLocale locale)
186            {
187                if (isDate()) {
188                    return new DateFormat(code, token, locale, false);
189                } else if (isNumeric()) {
190                    return new LiteralFormat(code, token);
191                } else if (isString()) {
192                    throw new Error();
193                } else {
194                    return new LiteralFormat(token);
195                }
196            }
197        }
198    
199        /**
200         * BasicFormat is the interface implemented by the classes which do all
201         * the work.  Whereas {@link Format} has only one method for formatting,
202         * {@link Format#format(Object)}, this class provides methods for several
203         * primitive types.  To make it easy to combine formatting objects, all
204         * methods write to a {@link PrintWriter}.
205         *
206         * The base implementation of most of these methods throws an error, there
207         * is no requirement that a derived class implements all of these methods.
208         * It is up to {@link Format#parseFormatString} to ensure that, for example,
209         * the {@link #format(double,StringBuilder)} method is never called for
210         * {@link DateFormat}.
211         */
212        static class BasicFormat {
213            int code;
214    
215            BasicFormat() {
216                this(0);
217            }
218    
219            BasicFormat(int code) {
220                this.code = code;
221            }
222    
223            boolean isNumeric() {
224                return false;
225            }
226    
227            boolean isDate() {
228                return false;
229            }
230    
231            boolean isString() {
232                return false;
233            }
234    
235            void formatNull(StringBuilder buf) {
236            }
237    
238            void format(double d, StringBuilder buf) {
239                throw new Error();
240            }
241    
242            void format(long n, StringBuilder buf) {
243                throw new Error();
244            }
245    
246            void format(String s, StringBuilder buf) {
247                throw new Error();
248            }
249    
250            void format(Date date, StringBuilder buf) {
251                Calendar calendar = Calendar.getInstance(); // todo: use locale
252                calendar.setTime(date);
253                format(calendar, buf);
254            }
255    
256            void format(Calendar calendar, StringBuilder buf) {
257                throw new Error();
258            }
259    
260            /**
261             * Returns whether this format can handle a given value.
262             *
263             * <p>Usually returns true;
264             * one notable exception is a format for negative numbers which
265             * causes the number to be underflow to zero and therefore be
266             * ineligible for the negative format.
267             *
268             * @param n value
269             * @return Whether this format is applicable for a given value
270             */
271            boolean isApplicableTo(double n) {
272                return true;
273            }
274    
275            /**
276             * Returns whether this format can handle a given value.
277             *
278             * <p>Usually returns true;
279             * one notable exception is a format for negative numbers which
280             * causes the number to be underflow to zero and therefore be
281             * ineligible for the negative format.
282             *
283             * @param n value
284             * @return Whether this format is applicable for a given value
285             */
286            boolean isApplicableTo(long n) {
287                return true;
288            }
289        }
290    
291        /**
292         * AlternateFormat is an implementation of {@link Format.BasicFormat} which
293         * allows a different format to be used for different kinds of values.  If
294         * there are 4 formats, purposes are as follows:<ol>
295         * <li>positive numbers</li>
296         * <li>negative numbers</li>
297         * <li>zero</li>
298         * <li>null values</li>
299         * </ol>
300         *
301         * If there are fewer than 4 formats, the first is used as a fall-back.
302         * See the <a href="http://www.apostate.com/programming/vb-format.html">the
303         * visual basic format specification</a> for more details.
304         */
305        static class AlternateFormat extends BasicFormat {
306            final BasicFormat[] formats;
307    
308            AlternateFormat(BasicFormat[] formats)
309            {
310                this.formats = formats;
311                assert formats.length >= 2;
312            }
313    
314            void formatNull(StringBuilder buf) {
315                if (formats.length >= 4) {
316                    formats[3].format(0, buf);
317                } else {
318                    super.formatNull(buf);
319                }
320            }
321    
322            void format(double n, StringBuilder buf) {
323                if (formats.length == 0) {
324                    buf.append(n);
325                } else {
326                    int i;
327                    if (n == 0 &&
328                        formats.length >= 3 &&
329                        formats[2] != null) {
330                        i = 2;
331                    } else if (n < 0 &&
332                               formats.length >= 2 &&
333                               formats[1] != null) {
334                        if (formats[1].isApplicableTo(n)) {
335                            n = -n;
336                            i = 1;
337                        } else {
338                            // Does not fit into the negative mask, so use the nil
339                            // mask. For example, "#.0;(#.0);Nil" formats -0.0001
340                            // as "Nil".
341                            i = 2;
342                        }
343                    } else {
344                        i = 0;
345                    }
346                    formats[i].format(n, buf);
347                }
348            }
349    
350            void format(long n, StringBuilder buf) {
351                if (formats.length == 0) {
352                    buf.append(n);
353                } else {
354                    int i;
355                    if (n == 0 &&
356                        formats.length >= 3 &&
357                        formats[2] != null) {
358                        i = 2;
359                    } else if (n < 0 &&
360                               formats.length >= 2 &&
361                               formats[1] != null &&
362                               formats[1].isApplicableTo(n)) {
363                        n = -n;
364                        i = 1;
365                    } else {
366                        i = 0;
367                    }
368                    formats[i].format(n, buf);
369                }
370            }
371    
372            void format(String s, StringBuilder buf) {
373                formats[0].format(s, buf);
374            }
375    
376            void format(Date date, StringBuilder buf) {
377                formats[0].format(date, buf);
378            }
379    
380            void format(Calendar calendar, StringBuilder buf) {
381                formats[0].format(calendar, buf);
382            }
383        }
384    
385        /**
386         * LiteralFormat is an implementation of {@link Format.BasicFormat} which
387         * prints a constant value, regardless of the value to be formatted.
388         *
389         * @see CompoundFormat
390         */
391        static class LiteralFormat extends BasicFormat
392        {
393            String s;
394    
395            LiteralFormat(String s)
396            {
397                this(FORMAT_LITERAL, s);
398            }
399    
400            LiteralFormat(int code, String s)
401            {
402                super(code);
403                this.s = s;
404            }
405    
406            void format(double d, StringBuilder buf) {
407                buf.append(s);
408            }
409    
410            void format(long n, StringBuilder buf) {
411                buf.append(s);
412            }
413    
414            void format(String s, StringBuilder buf) {
415                buf.append(s);
416            }
417    
418            void format(Date date, StringBuilder buf) {
419                buf.append(s);
420            }
421    
422            void format(Calendar calendar, StringBuilder buf) {
423                buf.append(s);
424            }
425        }
426    
427        /**
428         * CompoundFormat is an implementation of {@link Format.BasicFormat} where
429         * each value is formatted by applying a sequence of format elements.  Each
430         * format element is itself a format.
431         *
432         * @see AlternateFormat
433         */
434        static class CompoundFormat extends BasicFormat
435        {
436            final BasicFormat[] formats;
437            CompoundFormat(BasicFormat[] formats)
438            {
439                this.formats = formats;
440                assert formats.length >= 2;
441            }
442    
443            void formatNull(StringBuilder buf) {
444                for (int i = 0; i < formats.length; i++) {
445                    formats[i].formatNull(buf);
446                }
447            }
448    
449            void format(double v, StringBuilder buf) {
450                for (int i = 0; i < formats.length; i++) {
451                    formats[i].format(v, buf);
452                }
453            }
454    
455            void format(long v, StringBuilder buf) {
456                for (int i = 0; i < formats.length; i++) {
457                    formats[i].format(v, buf);
458                }
459            }
460    
461            void format(String v, StringBuilder buf) {
462                for (int i = 0; i < formats.length; i++) {
463                    formats[i].format(v, buf);
464                }
465            }
466    
467            void format(Date v, StringBuilder buf) {
468                for (int i = 0; i < formats.length; i++) {
469                    formats[i].format(v, buf);
470                }
471            }
472    
473            void format(Calendar v, StringBuilder buf) {
474                for (int i = 0; i < formats.length; i++) {
475                    formats[i].format(v, buf);
476                }
477            }
478    
479            boolean isApplicableTo(double n) {
480                for (int i = 0; i < formats.length; i++) {
481                    if (!formats[i].isApplicableTo(n)) {
482                        return false;
483                    }
484                }
485                return true;
486            }
487    
488        }
489    
490        /**
491         * JavaFormat is an implementation of {@link Format.BasicFormat} which
492         * prints values using Java's default formatting for their type.
493         * <code>null</code> values appear as an empty string.
494         */
495        static class JavaFormat extends BasicFormat
496        {
497            private final NumberFormat numberFormat;
498            private final java.text.DateFormat dateFormat;
499    
500            JavaFormat(Locale locale)
501            {
502                this.numberFormat = NumberFormat.getNumberInstance(locale);
503                this.dateFormat = java.text.DateFormat.getDateInstance(
504                        java.text.DateFormat.SHORT, locale);
505            }
506    
507            // No need to override format(Object,PrintWriter) or
508            // format(Date,PrintWriter).
509    
510            void format(double d, StringBuilder buf) {
511                // NOTE (jhyde, 2006/12/1): We'd use
512                // NumberFormat(double,StringBuilder,FieldPosition) if it existed.
513                buf.append(numberFormat.format(d));
514            }
515    
516            void format(long n, StringBuilder buf) {
517                // NOTE (jhyde, 2006/12/1): We'd use
518                // NumberFormat(long,StringBuilder,FieldPosition) if it existed.
519                buf.append(numberFormat.format(n));
520            }
521    
522            void format(String s, StringBuilder buf) {
523                buf.append(s);
524            }
525    
526            void format(Calendar calendar, StringBuilder buf) {
527                // NOTE (jhyde, 2006/12/1): We'd use
528                // NumberFormat(Date,StringBuilder,FieldPosition) if it existed.
529                buf.append(dateFormat.format(calendar.getTime()));
530            }
531        }
532    
533        /**
534         * FallbackFormat catches un-handled datatypes and prints the original
535         * format string.  Better than giving an error.  Abstract base class for
536         * NumericFormat and DateFormat.
537         */
538        static abstract class FallbackFormat extends BasicFormat
539        {
540            String token;
541    
542            FallbackFormat(int code, String token)
543            {
544                super(code);
545                this.token = token;
546            }
547    
548            void format(double d, StringBuilder buf) {
549                buf.append(token);
550            }
551    
552            void format(long n, StringBuilder buf) {
553                buf.append(token);
554            }
555    
556            void format(String s, StringBuilder buf) {
557                buf.append(token);
558            }
559    
560            void format(Calendar calendar, StringBuilder buf) {
561                buf.append(token);
562            }
563        }
564    
565        /**
566         * NumericFormat is an implementation of {@link Format.BasicFormat} which
567         * prints numbers with a given number of decimal places, leading zeroes, in
568         * exponential notation, etc.
569         *
570         * <p>It is implemented using {@link FloatingDecimal}, which is a
571         * barely-modified version of <code>java.lang.FloatingDecimal</code>.
572         */
573        static class NumericFormat extends FallbackFormat
574        {
575            FormatLocale locale;
576            int digitsLeftOfPoint;
577            int zeroesLeftOfPoint;
578            int digitsRightOfPoint;
579            int zeroesRightOfPoint;
580            int digitsRightOfExp;
581            int zeroesRightOfExp;
582    
583            /**
584             * Number of decimal places to shift the number left before
585             * formatting it: 2 means multiply by 100; -3 means divide by
586             * 1000.
587             */
588            int decimalShift;
589            char expChar;
590            boolean expSign;
591            boolean useDecimal; // not used
592            boolean useThouSep;
593    
594            NumericFormat(
595                String token, FormatLocale locale,
596                int expFormat,
597                int digitsLeftOfPoint, int zeroesLeftOfPoint,
598                int digitsRightOfPoint, int zeroesRightOfPoint,
599                int digitsRightOfExp, int zeroesRightOfExp,
600                boolean useDecimal, boolean useThouSep)
601            {
602                super(FORMAT_NULL, token);
603                this.locale = locale;
604                switch (expFormat) {
605                case FORMAT_E_MINUS_UPPER:
606                    this.expChar = 'E';
607                    this.expSign = false;
608                    break;
609                case FORMAT_E_PLUS_UPPER:
610                    this.expChar = 'E';
611                    this.expSign = true;
612                    break;
613                case FORMAT_E_MINUS_LOWER:
614                    this.expChar = 'e';
615                    this.expSign = false;
616                    break;
617                case FORMAT_E_PLUS_LOWER:
618                    this.expChar = 'e';
619                    this.expSign = true;
620                    break;
621                default:
622                    this.expChar = 0;
623                    this.expSign = false;
624                }
625                this.digitsLeftOfPoint = digitsLeftOfPoint;
626                this.zeroesLeftOfPoint = zeroesLeftOfPoint;
627                this.digitsRightOfPoint = digitsRightOfPoint;
628                this.zeroesRightOfPoint = zeroesRightOfPoint;
629                this.digitsRightOfExp = digitsRightOfExp;
630                this.zeroesRightOfExp = zeroesRightOfExp;
631                this.useDecimal = useDecimal;
632                this.useThouSep = useThouSep;
633                this.decimalShift = 0; // set later
634            }
635    
636            void format(double n, StringBuilder buf)
637            {
638                FloatingDecimal fd = new FloatingDecimal(n);
639                fd.shift(decimalShift);
640                final int formatDigitsRightOfPoint =
641                        zeroesRightOfPoint + digitsRightOfPoint;
642                if (n == 0.0 || (n < 0 && !shows(fd, formatDigitsRightOfPoint))) {
643                    // Underflow of negative number. Make it zero, so there is no
644                    // '-' sign.
645                    n = 0;
646                    fd = new FloatingDecimal(0);
647                }
648                String s = fd.toJavaFormatString(
649                    zeroesLeftOfPoint,
650                    locale.decimalPlaceholder,
651                    zeroesRightOfPoint,
652                        formatDigitsRightOfPoint,
653                    expChar,
654                    expSign,
655                    zeroesRightOfExp,
656                    useThouSep ? locale.thousandSeparator : '\0');
657                buf.append(s);
658            }
659    
660            boolean isApplicableTo(double n) {
661                if (n >= 0) {
662                    return true;
663                }
664                FloatingDecimal fd = new FloatingDecimal(n);
665                fd.shift(decimalShift);
666                final int formatDigitsRightOfPoint =
667                        zeroesRightOfPoint + digitsRightOfPoint;
668                return shows(fd, formatDigitsRightOfPoint);
669            }
670    
671            private static boolean shows(
672                    FloatingDecimal fd, int formatDigitsRightOfPoint) {
673                final int i0 = - fd.decExponent - formatDigitsRightOfPoint;
674                if (i0 < 0) {
675                    return true;
676                }
677                if (i0 > 0) {
678                    return false;
679                }
680                if (fd.digits[0] >= '5') {
681                    return true;
682                }
683                return false;
684            }
685    
686            void format(long n, StringBuilder buf)
687            {
688                mondrian.util.Format.FloatingDecimal fd
689                    = new mondrian.util.Format.FloatingDecimal(n);
690                fd.shift(decimalShift);
691                String s = fd.toJavaFormatString(
692                    zeroesLeftOfPoint,
693                    locale.decimalPlaceholder,
694                    zeroesRightOfPoint,
695                    zeroesRightOfPoint + digitsRightOfPoint,
696                    expChar,
697                    expSign,
698                    zeroesRightOfExp,
699                    useThouSep ? locale.thousandSeparator : '\0');
700                buf.append(s);
701            }
702        }
703    
704        /**
705         * DateFormat is an element of a {@link Format.CompoundFormat} which has a
706         * value when applied to a {@link Calendar} object.  (Values of type {@link
707         * Date} are automatically converted into {@link Calendar}s when you call
708         * {@link Format.BasicFormat#format(java.util.Date,StringBuilder)} calls to format
709         * other kinds of values give a runtime error.)
710         *
711         * <p>In a typical use of this class, a format string such as "m/d/yy" is
712         * parsed into DateFormat objects for "m", "d", and "yy", and {@link
713         * LiteralFormat} objects for "/".  A {@link Format.CompoundFormat} object
714         * is created to bind them together.
715         */
716        static class DateFormat extends FallbackFormat
717        {
718            FormatLocale locale;
719            boolean twelveHourClock;
720    
721            DateFormat(int code, String s, FormatLocale locale, boolean twelveHourClock)
722            {
723                super(code, s);
724                this.locale = locale;
725                this.twelveHourClock = twelveHourClock;
726            }
727    
728            void setTwelveHourClock(boolean twelveHourClock)
729            {
730                this.twelveHourClock = twelveHourClock;
731            }
732    
733            void format(Calendar calendar, StringBuilder buf)
734            {
735                format(code, calendar, buf);
736            }
737    
738            private void format(int code, Calendar calendar, StringBuilder buf)
739            {
740                switch (code) {
741                case FORMAT_C:
742                {
743                    boolean dateSet = !(
744                        calendar.get(Calendar.DAY_OF_YEAR) == 0 &&
745                        calendar.get(Calendar.YEAR) == 0);
746                    boolean timeSet = !(
747                        calendar.get(Calendar.SECOND) == 0 &&
748                        calendar.get(Calendar.MINUTE) == 0 &&
749                        calendar.get(Calendar.HOUR) == 0);
750                    if (dateSet) {
751                        format(FORMAT_DDDDD, calendar, buf);
752                    }
753                    if (dateSet && timeSet) {
754                        buf.append(' ');
755                    }
756                    if (timeSet) {
757                        format(FORMAT_TTTTT, calendar, buf);
758                    }
759                    break;
760                }
761                case FORMAT_D:
762                {
763                    int d = calendar.get(Calendar.DAY_OF_MONTH);
764                    buf.append(d);
765                    break;
766                }
767                case FORMAT_DD:
768                {
769                    int d = calendar.get(Calendar.DAY_OF_MONTH);
770                    if (d < 10) {
771                        buf.append('0');
772                    }
773                    buf.append(d);
774                    break;
775                }
776                case FORMAT_DDD:
777                {
778                    int dow = calendar.get(Calendar.DAY_OF_WEEK);
779                    buf.append(locale.daysOfWeekShort[dow]); // e.g. Sun
780                    break;
781                }
782                case FORMAT_DDDD:
783                {
784                    int dow = calendar.get(Calendar.DAY_OF_WEEK);
785                    buf.append(locale.daysOfWeekLong[dow]); // e.g. Sunday
786                    break;
787                }
788                case FORMAT_DDDDD:
789                {
790                    // Officially, we should use the system's short date
791                    // format. But for now, we always print using the default
792                    // format, m/d/yy.
793                    format(FORMAT_M, calendar,buf);
794                    buf.append(locale.dateSeparator);
795                    format(FORMAT_D, calendar,buf);
796                    buf.append(locale.dateSeparator);
797                    format(FORMAT_YY, calendar,buf);
798                    break;
799                }
800                case FORMAT_DDDDDD:
801                {
802                    format(FORMAT_MMMM_UPPER, calendar, buf);
803                    buf.append(" ");
804                    format(FORMAT_DD, calendar, buf);
805                    buf.append(", ");
806                    format(FORMAT_YYYY, calendar, buf);
807                    break;
808                }
809                case FORMAT_W:
810                {
811                    int dow = calendar.get(Calendar.DAY_OF_WEEK);
812                    buf.append(dow);
813                    break;
814                }
815                case FORMAT_WW:
816                {
817                    int woy = calendar.get(Calendar.WEEK_OF_YEAR);
818                    buf.append(woy);
819                    break;
820                }
821                case FORMAT_M:
822                {
823                    int m = calendar.get(Calendar.MONTH) + 1; // 0-based
824                    buf.append(m);
825                    break;
826                }
827                case FORMAT_MM:
828                {
829                    int mm = calendar.get(Calendar.MONTH) + 1; // 0-based
830                    if (mm < 10) {
831                        buf.append('0');
832                    }
833                    buf.append(mm);
834                    break;
835                }
836                case FORMAT_MMM_LOWER:
837                case FORMAT_MMM_UPPER:
838                {
839                    int m = calendar.get(Calendar.MONTH); // 0-based
840                    buf.append(locale.monthsShort[m]); // e.g. Jan
841                    break;
842                }
843                case FORMAT_MMMM_LOWER:
844                case FORMAT_MMMM_UPPER:
845                {
846                    int m = calendar.get(Calendar.MONTH); // 0-based
847                    buf.append(locale.monthsLong[m]); // e.g. January
848                    break;
849                }
850                case FORMAT_Q:
851                {
852                    int m = calendar.get(Calendar.MONTH);
853                    // 0(Jan) -> q1, 1(Feb) -> q1, 2(Mar) -> q1, 3(Apr) -> q2
854                    int q = m / 3 + 1;
855                    buf.append(q);
856                    break;
857                }
858                case FORMAT_Y:
859                {
860                    int doy = calendar.get(Calendar.DAY_OF_YEAR);
861                    buf.append(doy);
862                    break;
863                }
864                case FORMAT_YY:
865                {
866                    int y = calendar.get(Calendar.YEAR) % 100;
867                    if (y < 10) {
868                        buf.append('0');
869                    }
870                    buf.append(y);
871                    break;
872                }
873                case FORMAT_YYYY:
874                {
875                    int y = calendar.get(Calendar.YEAR);
876                    buf.append(y);
877                    break;
878                }
879                case FORMAT_H:
880                {
881                    int h = calendar.get(
882                        twelveHourClock ? Calendar.HOUR : Calendar.HOUR_OF_DAY);
883                    buf.append(h);
884                    break;
885                }
886                case FORMAT_HH:
887                {
888                    int h = calendar.get(
889                        twelveHourClock ? Calendar.HOUR : Calendar.HOUR_OF_DAY);
890                    if (h < 10) {
891                        buf.append('0');
892                    }
893                    buf.append(h);
894                    break;
895                }
896                case FORMAT_N:
897                {
898                    int n = calendar.get(Calendar.MINUTE);
899                    buf.append(n);
900                    break;
901                }
902                case FORMAT_NN:
903                {
904                    int n = calendar.get(Calendar.MINUTE);
905                    if (n < 10) {
906                        buf.append('0');
907                    }
908                    buf.append(n);
909                    break;
910                }
911                case FORMAT_S:
912                {
913                    int s = calendar.get(Calendar.SECOND);
914                    buf.append(s);
915                    break;
916                }
917                case FORMAT_SS:
918                {
919                    int s = calendar.get(Calendar.SECOND);
920                    if (s < 10) {
921                        buf.append('0');
922                    }
923                    buf.append(s);
924                    break;
925                }
926                case FORMAT_TTTTT:
927                {
928                    // Officially, we should use the system's time format. But
929                    // for now, we always print using the default format, h:mm:ss.
930                    format(FORMAT_H, calendar,buf);
931                    buf.append(locale.timeSeparator);
932                    format(FORMAT_NN, calendar,buf);
933                    buf.append(locale.timeSeparator);
934                    format(FORMAT_SS, calendar,buf);
935                    break;
936                }
937                case FORMAT_AMPM:
938                case FORMAT_UPPER_AM_SOLIDUS_PM:
939                {
940                    boolean isAm = calendar.get(Calendar.AM_PM) == Calendar.AM;
941                    buf.append(isAm ? "AM" : "PM");
942                    break;
943                }
944                case FORMAT_LOWER_AM_SOLIDUS_PM:
945                {
946                    boolean isAm = calendar.get(Calendar.AM_PM) == Calendar.AM;
947                    buf.append(isAm ? "am" : "pm");
948                    break;
949                }
950                case FORMAT_UPPER_A_SOLIDUS_P:
951                {
952                    boolean isAm = calendar.get(Calendar.AM_PM) == Calendar.AM;
953                    buf.append(isAm ? "A" : "P");
954                    break;
955                }
956                case FORMAT_LOWER_A_SOLIDUS_P:
957                {
958                    boolean isAm = calendar.get(Calendar.AM_PM) == Calendar.AM;
959                    buf.append(isAm ? "a" : "p");
960                    break;
961                }
962                default:
963                    throw new Error();
964                }
965            }
966        }
967    
968        /**
969         * A FormatLocale contains all information necessary to format objects
970         * based upon the locale of the end-user.  Use {@link Format#createLocale}
971         * to make one.
972         */
973        public static class FormatLocale
974        {
975            char thousandSeparator;
976            char decimalPlaceholder;
977            String dateSeparator;
978            String timeSeparator;
979            String currencySymbol;
980            String currencyFormat;
981            String[] daysOfWeekShort;
982            String[] daysOfWeekLong;
983            String[] monthsShort;
984            String[] monthsLong;
985            private final Locale locale;
986    
987            private FormatLocale(
988                    char thousandSeparator,
989                    char decimalPlaceholder,
990                    String dateSeparator,
991                    String timeSeparator,
992                    String currencySymbol,
993                    String currencyFormat,
994                    String[] daysOfWeekShort,
995                    String[] daysOfWeekLong,
996                    String[] monthsShort,
997                    String[] monthsLong,
998                    Locale locale)
999            {
1000                this.locale = locale;
1001                if (thousandSeparator == '\0') {
1002                    thousandSeparator = thousandSeparator_en;
1003                }
1004                this.thousandSeparator = thousandSeparator;
1005                if (decimalPlaceholder == '\0') {
1006                    decimalPlaceholder = decimalPlaceholder_en;
1007                }
1008                this.decimalPlaceholder = decimalPlaceholder;
1009                if (dateSeparator == null) {
1010                    dateSeparator = dateSeparator_en;
1011                }
1012                this.dateSeparator = dateSeparator;
1013                if (timeSeparator == null) {
1014                    timeSeparator = timeSeparator_en;
1015                }
1016                this.timeSeparator = timeSeparator;
1017                if (currencySymbol == null) {
1018                    currencySymbol = currencySymbol_en;
1019                }
1020                this.currencySymbol = currencySymbol;
1021                if (currencyFormat == null) {
1022                    currencyFormat = currencyFormat_en;
1023                }
1024                this.currencyFormat = currencyFormat;
1025                if (daysOfWeekShort == null) {
1026                    daysOfWeekShort = daysOfWeekShort_en;
1027                }
1028                this.daysOfWeekShort = daysOfWeekShort;
1029                if (daysOfWeekLong == null) {
1030                    daysOfWeekLong = daysOfWeekLong_en;
1031                }
1032                this.daysOfWeekLong = daysOfWeekLong;
1033                if (monthsShort == null) {
1034                    monthsShort = monthsShort_en;
1035                }
1036                this.monthsShort = monthsShort;
1037                if (monthsLong == null) {
1038                    monthsLong = monthsLong_en;
1039                }
1040                this.monthsLong = monthsLong;
1041                if (daysOfWeekShort.length != 8 ||
1042                    daysOfWeekLong.length != 8 ||
1043                    monthsShort.length != 13 ||
1044                    monthsLong.length != 13) {
1045                    throw new IllegalArgumentException(
1046                        "Format: day or month array has incorrect length");
1047                }
1048            }
1049    
1050    //          /**
1051    //           * Get the localized string for day of week, given
1052    //           * an <CODE>int</CODE> day value, with 0 = SUNDAY.
1053    //           */
1054    //          public static String getDayOfWeek(int day)
1055    //          {
1056    //              LocaleResource localeResource = FormatLocale.getResource();
1057    //              switch (day)
1058    //              {
1059    //              case 0: return localeResource.getsunday();
1060    //              case 1: return localeResource.getmonday();
1061    //              case 2: return localeResource.gettuesday();
1062    //              case 3: return localeResource.getwednesday();
1063    //              case 4: return localeResource.getthursday();
1064    //              case 5: return localeResource.getfriday();
1065    //              case 6: return localeResource.getsaturday();
1066    //              default: throw new IllegalArgumentException();
1067    //              }
1068    //          }
1069    
1070    //          /**
1071    //           * Get the localized string for month of year, given
1072    //           * an <CODE>int</CODE> month value, with 0 = JANUARY.
1073    //           */
1074    //          public static String getMonthOfYear(int month)
1075    //          {
1076    //              LocaleResource localeResource = FormatLocale.getResource();
1077    //              switch (month)
1078    //              {
1079    //              case 0: return localeResource.getjanuary();
1080    //              case 1: return localeResource.getfebruary();
1081    //              case 2: return localeResource.getmarch();
1082    //              case 3: return localeResource.getapril();
1083    //              case 4: return localeResource.getmay();
1084    //              case 5: return localeResource.getjune();
1085    //              case 6: return localeResource.getjuly();
1086    //              case 7: return localeResource.getaugust();
1087    //              case 8: return localeResource.getseptember();
1088    //              case 9: return localeResource.getoctober();
1089    //              case 10: return localeResource.getnovember();
1090    //              case 11: return localeResource.getdecember();
1091    //              default: throw new IllegalArgumentException();
1092    //              }
1093    //          }
1094    
1095    //          /**
1096    //           * Get the string representation of the calendar
1097    //           * quarter for a given quarter and year.  Subclasses
1098    //           * should override this method.
1099    //           */
1100    //          public static String getCalendarQuarter(int quarterIn, int yearIn)
1101    //          {
1102    //              Integer year = new Integer (yearIn % 100);
1103    //              Integer quarter = new Integer(quarterIn);
1104    
1105    //              String strYear = (year.intValue() < 10)
1106    //                  ? "0" + year.toString() : year.toString();
1107    //              LocaleResource localeResource = FormatLocale.getResource();
1108    //              String ret = localeResource.getcalendarQuarter(quarter.toString(), strYear);
1109    
1110    //              return ret;
1111    //          }
1112    
1113    //          /**
1114    //           * Get the string representation of the fiscal
1115    //           * quarter for a given quarter and year.  Subclasses
1116    //           * should override this method.
1117    //           */
1118    //          public static String getFiscalQuarter(int quarterIn, int yearIn)
1119    //          {
1120    //              Integer year = new Integer (yearIn % 100);
1121    //              Integer quarter = new Integer(quarterIn);
1122    
1123    //              String strYear = (year.intValue() < 10)
1124    //                  ? "0" + year.toString() : year.toString();
1125    
1126    //              LocaleResource localeResource = FormatLocale.getResource();
1127    //              String ret = localeResource.getfiscalQuarter(quarter.toString(),
1128    //                                                            strYear);
1129    //              return ret;
1130    //          }
1131    
1132        }
1133    
1134        private static class StringFormat extends BasicFormat
1135        {
1136            int stringCase;
1137    
1138            StringFormat(int stringCase) {
1139                this.stringCase = stringCase;
1140            }
1141        }
1142    
1143        /** Values for {@link StringFormat#stringCase}. */
1144        private static final int CASE_ASIS = 0;
1145        private static final int CASE_UPPER = 1;
1146        private static final int CASE_LOWER = 2;
1147    
1148        /** Types of Format. */
1149        private static final int GENERAL = 0;
1150        private static final int DATE = 3;
1151        private static final int NUMERIC = 4;
1152        private static final int STRING = 5;
1153        /** A Format is flagged SPECIAL if it needs special processing
1154         * during parsing. */
1155        private static final int SPECIAL = 8;
1156    
1157        /** Values for {@link Format.BasicFormat#code}. */
1158        private static final int FORMAT_NULL = 0;
1159        private static final int FORMAT_C = 3;
1160        private static final int FORMAT_D = 4;
1161        private static final int FORMAT_DD = 5;
1162        private static final int FORMAT_DDD = 6;
1163        private static final int FORMAT_DDDD = 7;
1164        private static final int FORMAT_DDDDD = 8;
1165        private static final int FORMAT_DDDDDD = 9;
1166        private static final int FORMAT_W = 10;
1167        private static final int FORMAT_WW = 11;
1168        private static final int FORMAT_M = 12;
1169        private static final int FORMAT_MM = 13;
1170        private static final int FORMAT_MMM_UPPER = 14;
1171        private static final int FORMAT_MMMM_UPPER = 15;
1172        private static final int FORMAT_Q = 16;
1173        private static final int FORMAT_Y = 17;
1174        private static final int FORMAT_YY = 18;
1175        private static final int FORMAT_YYYY = 19;
1176        private static final int FORMAT_H = 20;
1177        private static final int FORMAT_HH = 21;
1178        private static final int FORMAT_N = 22;
1179        private static final int FORMAT_NN = 23;
1180        private static final int FORMAT_S = 24;
1181        private static final int FORMAT_SS = 25;
1182        private static final int FORMAT_TTTTT = 26;
1183        private static final int FORMAT_UPPER_AM_SOLIDUS_PM = 27;
1184        private static final int FORMAT_LOWER_AM_SOLIDUS_PM = 28;
1185        private static final int FORMAT_UPPER_A_SOLIDUS_P = 29;
1186        private static final int FORMAT_LOWER_A_SOLIDUS_P = 30;
1187        private static final int FORMAT_AMPM = 31;
1188        private static final int FORMAT_0 = 32;
1189        private static final int FORMAT_POUND = 33;
1190        private static final int FORMAT_DECIMAL = 34;
1191        private static final int FORMAT_PERCENT = 35;
1192        private static final int FORMAT_THOUSEP = 36;
1193        private static final int FORMAT_TIMESEP = 37;
1194        private static final int FORMAT_DATESEP = 38;
1195        private static final int FORMAT_E_MINUS_UPPER = 39;
1196        private static final int FORMAT_E_PLUS_UPPER = 40;
1197        private static final int FORMAT_E_MINUS_LOWER = 41;
1198        private static final int FORMAT_E_PLUS_LOWER = 42;
1199        private static final int FORMAT_LITERAL = 43;
1200        private static final int FORMAT_BACKSLASH = 44;
1201        private static final int FORMAT_QUOTE = 45;
1202        private static final int FORMAT_CHARACTER_OR_SPACE = 46;
1203        private static final int FORMAT_CHARACTER_OR_NOTHING = 47;
1204        private static final int FORMAT_LOWER = 48;
1205        private static final int FORMAT_UPPER = 49;
1206        private static final int FORMAT_FILL_FROM_LEFT = 50;
1207        private static final int FORMAT_SEMI = 51;
1208        private static final int FORMAT_GENERAL_NUMBER = 52;
1209        private static final int FORMAT_GENERAL_DATE = 53;
1210        private static final int FORMAT_INTL_CURRENCY = 54;
1211        private static final int FORMAT_MMM_LOWER = 55;
1212        private static final int FORMAT_MMMM_LOWER = 56;
1213        private static final int FORMAT_USD = 57;
1214    
1215        private static final Token nfe(
1216            int code, int flags, String token, String purpose, String description)
1217        {
1218            Util.discard(purpose);
1219            Util.discard(description);
1220            return new Token(code,flags,token);
1221        }
1222    
1223        public static final List<Token> getTokenList()
1224        {
1225            return Collections.unmodifiableList(Arrays.asList(tokens));
1226        }
1227    
1228        static final Token[] tokens = {
1229            nfe(FORMAT_NULL                , NUMERIC, null, "No formatting", "Display the number with no formatting."),
1230            nfe(FORMAT_C                   , DATE, "C", null, "Display the date as ddddd and display the time as t t t t t, in that order. Display only date information if there is no fractional part to the date serial number; display only time information if there is no integer portion."),
1231            nfe(FORMAT_D                   , DATE, "d", null, "Display the day as a number without a leading zero (1 - 31)."),
1232            nfe(FORMAT_DD                  , DATE, "dd", null, "Display the day as a number with a leading zero (01 - 31)."),
1233            nfe(FORMAT_DDD                 , DATE, "Ddd", null, "Display the day as an abbreviation (Sun - Sat)."),
1234            nfe(FORMAT_DDDD                , DATE, "dddd", null, "Display the day as a full name (Sunday - Saturday)."),
1235            nfe(FORMAT_DDDDD               , DATE, "ddddd", null, "Display the date as a complete date (including day, month, and year), formatted according to your system's short date format setting. The default short date format is m/d/yy."),
1236            nfe(FORMAT_DDDDDD              , DATE, "dddddd", null, "Display a date serial number as a complete date (including day, month, and year) formatted according to the long date setting recognized by your system. The default long date format is mmmm dd, yyyy."),
1237            nfe(FORMAT_W                   , DATE, "w", null, "Display the day of the week as a number (1 for Sunday through 7 for Saturday)."),
1238            nfe(FORMAT_WW                  , DATE, "ww", null, "Display the week of the year as a number (1 - 53)."),
1239            nfe(FORMAT_M                   , DATE | SPECIAL, "m", null, "Display the month as a number without a leading zero (1 - 12). If m immediately follows h or hh, the minute rather than the month is displayed."),
1240            nfe(FORMAT_MM                  , DATE | SPECIAL, "mm", null, "Display the month as a number with a leading zero (01 - 12). If m immediately follows h or hh, the minute rather than the month is displayed."),
1241            nfe(FORMAT_MMM_LOWER           , DATE, "mmm", null, "Display the month as an abbreviation (Jan - Dec)."),
1242            nfe(FORMAT_MMMM_LOWER          , DATE, "mmmm", null, "Display the month as a full month name (January - December)."),
1243            nfe(FORMAT_MMM_UPPER           , DATE, "mmm", null, "Display the month as an abbreviation (Jan - Dec)."),
1244            nfe(FORMAT_MMMM_UPPER          , DATE, "mmmm", null, "Display the month as a full month name (January - December)."),
1245            nfe(FORMAT_Q                   , DATE, "q", null, "Display the quarter of the year as a number (1 - 4)."),
1246            nfe(FORMAT_Y                   , DATE, "y", null, "Display the day of the year as a number (1 - 366)."),
1247            nfe(FORMAT_YY                  , DATE, "yy", null, "Display the year as a 2-digit number (00 - 99)."),
1248            nfe(FORMAT_YYYY                , DATE, "yyyy", null, "Display the year as a 4-digit number (100 - 9999)."),
1249            nfe(FORMAT_H                   , DATE, "h", null, "Display the hour as a number without leading zeros (0 - 23)."),
1250            nfe(FORMAT_HH                  , DATE, "hh", null, "Display the hour as a number with leading zeros (00 - 23)."),
1251            nfe(FORMAT_N                   , DATE, "n", null, "Display the minute as a number without leading zeros (0 - 59)."),
1252            nfe(FORMAT_NN                  , DATE, "nn", null, "Display the minute as a number with leading zeros (00 - 59)."),
1253            nfe(FORMAT_S                   , DATE, "s", null, "Display the second as a number without leading zeros (0 - 59)."),
1254            nfe(FORMAT_SS                  , DATE, "ss", null, "Display the second as a number with leading zeros (00 - 59)."),
1255            nfe(FORMAT_TTTTT               , DATE, "ttttt", null, "Display a time as a complete time (including hour, minute, and second), formatted using the time separator defined by the time format recognized by your system. A leading zero is displayed if the leading zero option is selected and the time is before 10:00 A.M. or P.M. The default time format is h:mm:ss."),
1256            nfe(FORMAT_UPPER_AM_SOLIDUS_PM , DATE, "AM/PM", null, "Use the 12-hour clock and display an uppercase AM with any hour before noon; display an uppercase PM with any hour between noon and 11:59 P.M."),
1257            nfe(FORMAT_LOWER_AM_SOLIDUS_PM , DATE, "am/pm", null, "Use the 12-hour clock and display a lowercase AM with any hour before noon; display a lowercase PM with any hour between noon and 11:59 P.M."),
1258            nfe(FORMAT_UPPER_A_SOLIDUS_P   , DATE, "A/P", null, "Use the 12-hour clock and display an uppercase A with any hour before noon; display an uppercase P with any hour between noon and 11:59 P.M."),
1259            nfe(FORMAT_LOWER_A_SOLIDUS_P   , DATE, "a/p", null, "Use the 12-hour clock and display a lowercase A with any hour before noon; display a lowercase P with any hour between noon and 11:59 P.M."),
1260            nfe(FORMAT_AMPM                , DATE, "AMPM", null, "Use the 12-hour clock and display the AM string literal as defined by your system with any hour before noon; display the PM string literal as defined by your system with any hour between noon and 11:59 P.M. AMPM can be either uppercase or lowercase, but the case of the string displayed matches the string as defined by your system settings. The default format is AM/PM."),
1261            nfe(FORMAT_0                   , NUMERIC | SPECIAL, "0", "Digit placeholder", "Display a digit or a zero. If the expression has a digit in the position where the 0 appears in the format string, display it; otherwise, display a zero in that position. If the number has fewer digits than there are zeros (on either side of the decimal) in the format expression, display leading or trailing zeros. If the number has more digits to the right of the decimal separator than there are zeros to the right of the decimal separator in the format expression, round the number to as many decimal places as there are zeros. If the number has more digits to the left of the decimal separator than there are zeros to the left of the decimal separator in the format expression, display the extra digits without modification."),
1262            nfe(FORMAT_POUND               , NUMERIC | SPECIAL, "#", "Digit placeholder", "Display a digit or nothing. If the expression has a digit in the position where the # appears in the format string, display it; otherwise, display nothing in that position.  This symbol works like the 0 digit placeholder, except that leading and trailing zeros aren't displayed if the number has the same or fewer digits than there are # characters on either side of the decimal separator in the format expression."),
1263            nfe(FORMAT_DECIMAL             , NUMERIC | SPECIAL, ".", "Decimal placeholder", "In some locales, a comma is used as the decimal separator. The decimal placeholder determines how many digits are displayed to the left and right of the decimal separator. If the format expression contains only number signs to the left of this symbol, numbers smaller than 1 begin with a decimal separator. If you always want a leading zero displayed with fractional numbers, use 0 as the first digit placeholder to the left of the decimal separator instead. The actual character used as a decimal placeholder in the formatted output depends on the Number Format recognized by your system."),
1264            nfe(FORMAT_PERCENT             , NUMERIC, "%", "Percent placeholder", "The expression is multiplied by 100. The percent character (%) is inserted in the position where it appears in the format string."),
1265            nfe(FORMAT_THOUSEP             , NUMERIC | SPECIAL, ",", "Thousand separator", "In some locales, a period is used as a thousand separator. The thousand separator separates thousands from hundreds within a number that has four or more places to the left of the decimal separator. Standard use of the thousand separator is specified if the format contains a thousand separator surrounded by digit placeholders (0 or #). Two adjacent thousand separators or a thousand separator immediately to the left of the decimal separator (whether or not a decimal is specified) means \"scale the number by dividing it by 1000, rounding as needed.\"  You can scale large numbers using this technique. For example, you can use the format string \"##0,,\" to represent 100 million as 100. Numbers smaller than 1 million are displayed as 0. Two adjacent thousand separators in any position other than immediately to the left of the decimal separator are treated simply as specifying the use of a thousand separator. The actual character used as the thousand separator in the formatted output depends on the Number Format recognized by your system."),
1266            nfe(FORMAT_TIMESEP             , DATE | SPECIAL, ":", "Time separator", "In some locales, other characters may be used to represent the time separator. The time separator separates hours, minutes, and seconds when time values are formatted. The actual character used as the time separator in formatted output is determined by your system settings."),
1267            nfe(FORMAT_DATESEP             , DATE | SPECIAL, "/", "Date separator", "In some locales, other characters may be used to represent the date separator. The date separator separates the day, month, and year when date values are formatted. The actual character used as the date separator in formatted output is determined by your system settings."),
1268            nfe(FORMAT_E_MINUS_UPPER       , NUMERIC | SPECIAL, "E-", "Scientific format", "If the format expression contains at least one digit placeholder (0 or #) to the right of E-, E+, e-, or e+, the number is displayed in scientific format and E or e is inserted between the number and its exponent. The number of digit placeholders to the right determines the number of digits in the exponent. Use E- or e- to place a minus sign next to negative exponents. Use E+ or e+ to place a minus sign next to negative exponents and a plus sign next to positive exponents."),
1269            nfe(FORMAT_E_PLUS_UPPER        , NUMERIC | SPECIAL, "E+", "Scientific format", "See E-."),
1270            nfe(FORMAT_E_MINUS_LOWER       , NUMERIC | SPECIAL, "e-", "Scientific format", "See E-."),
1271            nfe(FORMAT_E_PLUS_LOWER        , NUMERIC | SPECIAL, "e+", "Scientific format", "See E-."),
1272            nfe(FORMAT_LITERAL             , GENERAL, "-", "Display a literal character", "To display a character other than one of those listed, precede it with a backslash (\\) or enclose it in double quotation marks (\" \")."),
1273            nfe(FORMAT_LITERAL             , GENERAL, "+", "Display a literal character", "See -."),
1274            nfe(FORMAT_LITERAL             , GENERAL, "$", "Display a literal character", "See -."),
1275            nfe(FORMAT_LITERAL             , GENERAL, "(", "Display a literal character", "See -."),
1276            nfe(FORMAT_LITERAL             , GENERAL, ")", "Display a literal character", "See -."),
1277            nfe(FORMAT_LITERAL             , GENERAL, " ", "Display a literal character", "See -."),
1278            nfe(FORMAT_BACKSLASH           , GENERAL | SPECIAL, "\\", "Display the next character in the format string", "Many characters in the format expression have a special meaning and can't be displayed as literal characters unless they are preceded by a backslash. The backslash itself isn't displayed. Using a backslash is the same as enclosing the next character in double quotation marks. To display a backslash, use two backslashes (\\).  Examples of characters that can't be displayed as literal characters are the date- and time-formatting characters (a, c, d, h, m, n, p, q, s, t, w, y, and /:), the numeric-formatting characters (#, 0, %, E, e, comma, and period), and the string-formatting characters (@, &, <, >, and !)."),
1279            nfe(FORMAT_QUOTE               , GENERAL | SPECIAL, "\"", "Display the string inside the double quotation marks", "To include a string in format from within code, you must use Chr(34) to enclose the text (34 is the character code for a double quotation mark)."),
1280            nfe(FORMAT_CHARACTER_OR_SPACE  , STRING, "@", "Character placeholder", "Display a character or a space. If the string has a character in the position where the @ appears in the format string, display it; otherwise, display a space in that position. Placeholders are filled from right to left unless there is an ! character in the format string. See below."),
1281            nfe(FORMAT_CHARACTER_OR_NOTHING, STRING, "&", "Character placeholder", "Display a character or nothing. If the string has a character in the position where the & appears, display it; otherwise, display nothing. Placeholders are filled from right to left unless there is an ! character in the format string. See below."),
1282            nfe(FORMAT_LOWER               , STRING | SPECIAL, "<", "Force lowercase", "Display all characters in lowercase format."),
1283            nfe(FORMAT_UPPER               , STRING | SPECIAL, ">", "Force uppercase", "Display all characters in uppercase format."),
1284            nfe(FORMAT_FILL_FROM_LEFT      , STRING | SPECIAL, "!", "Force left to right fill of placeholders", "The default is to fill from right to left."),
1285            nfe(FORMAT_SEMI                , GENERAL | SPECIAL, ";", "Separates format strings for different kinds of values", "If there is one section, the format expression applies to all values. If there are two sections, the first section applies to positive values and zeros, the second to negative values. If there are three sections, the first section applies to positive values, the second to negative values, and the third to zeros. If there are four sections, the first section applies to positive values, the second to negative values, the third to zeros, and the fourth to Null values."),
1286            nfe(FORMAT_INTL_CURRENCY       , NUMERIC | SPECIAL, intlCurrencySymbol + "", null, "Display the locale's currency symbol."),
1287            nfe(FORMAT_USD                 , GENERAL, "USD", null, "Display USD (U.S. Dollars)."),
1288            nfe(FORMAT_GENERAL_NUMBER      , NUMERIC | SPECIAL, "General Number", null, "Shows numbers as entered."),
1289            nfe(FORMAT_GENERAL_DATE        , DATE | SPECIAL, "General Date", null, "Shows date and time if expression contains both. If expression is only a date or a time, the missing information is not displayed."),
1290        };
1291    
1292        static class MacroToken {
1293            String name;
1294            String translation;
1295            String description;
1296    
1297            MacroToken(String name, String translation, String description)
1298            {
1299                this.name = name;
1300                this.translation = translation;
1301                this.description = description;
1302            }
1303        }
1304    
1305        // Named formats.  todo: Supply the translation strings.
1306        private static final MacroToken[] macroTokens = {
1307            new MacroToken(
1308                "Currency", null, "Shows currency values according to the locale's CurrencyFormat.  Negative numbers are inside parentheses."),
1309            new MacroToken(
1310                "Fixed", "0", "Shows at least one digit."),
1311            new MacroToken(
1312                "Standard", "#,##0", "Uses a thousands separator."),
1313            new MacroToken(
1314                "Percent", "0.00%", "Multiplies the value by 100 with a percent sign at the end."),
1315            new MacroToken(
1316                "Scientific", "0.00e+00", "Uses standard scientific notation."),
1317            new MacroToken(
1318                "Long Date", "dddd, mmmm dd, yyyy", "Uses the Long Date format specified in the Regional Settings dialog box of the Microsoft Windows Control Panel."),
1319            new MacroToken(
1320                "Medium Date", "dd-mmm-yy", "Uses the dd-mmm-yy format (for example, 03-Apr-93)"),
1321            new MacroToken(
1322                "Short Date", "m/d/yy", "Uses the Short Date format specified in the Regional Settings dialog box of the Windows Control Panel."),
1323            new MacroToken(
1324                "Long Time", "h:mm:ss AM/PM", "Shows the hour, minute, second, and \"AM\" or \"PM\" using the h:mm:ss format."),
1325            new MacroToken(
1326                "Medium Time", "h:mm AM/PM", "Shows the hour, minute, and \"AM\" or \"PM\" using the \"hh:mm AM/PM\" format."),
1327            new MacroToken(
1328                "Short Time", "hh:mm", "Shows the hour and minute using the hh:mm format."),
1329            new MacroToken(
1330                "Yes/No", "\\Y\\e\\s;\\Y\\e\\s;\\N\\o;\\N\\o", "Any nonzero numeric value (usually - 1) is Yes. Zero is No."),
1331            new MacroToken(
1332                "True/False", "\\T\\r\\u\\e;\\T\\r\\u\\e;\\F\\a\\l\\s\\e;\\F\\a\\l\\s\\e", "Any nonzero numeric value (usually - 1) is True. Zero is False."),
1333            new MacroToken(
1334                "On/Off", "\\O\\n;\\O\\n;\\O\\f\\f;\\O\\f\\f", "Any nonzero numeric value (usually - 1) is On. Zero is Off."),
1335    
1336        };
1337    
1338        /**
1339         * Constructs a <code>Format</code> in a specific locale.
1340         *
1341         * @param formatString the format string; see
1342         *   <a href="http://www.apostate.com/programming/vb-format.html">this
1343         *   description</a> for more details
1344         * @param locale The locale
1345         */
1346        public Format(String formatString, Locale locale)
1347        {
1348            this(formatString, getBestFormatLocale(locale));
1349        }
1350    
1351        /**
1352         * Constructs a <code>Format</code> in a specific locale.
1353         *
1354         * @see FormatLocale
1355         * @see #createLocale
1356         */
1357        public Format(String formatString, FormatLocale locale)
1358        {
1359            if (formatString == null) {
1360                formatString = "";
1361            }
1362            this.formatString = formatString;
1363            if (locale == null) {
1364                locale = locale_US;
1365            }
1366            this.locale = locale;
1367    
1368            List<BasicFormat> alternateFormatList = new ArrayList<BasicFormat>();
1369            while (formatString.length() > 0) {
1370                formatString = parseFormatString(
1371                    formatString, alternateFormatList);
1372            }
1373    
1374            // If the format string is empty, use a Java format.
1375            // Later entries in the formats list default to the first (e.g.
1376            // "#.00;;Nil"), but the first entry must be set.
1377            if (alternateFormatList.size() == 0 || alternateFormatList.get(0) == null) {
1378                format = new JavaFormat(locale.locale);
1379            } else if (alternateFormatList.size() == 1) {
1380                format = (BasicFormat) alternateFormatList.get(0);
1381            } else {
1382                BasicFormat[] alternateFormats =
1383                        (BasicFormat[]) alternateFormatList.toArray(
1384                                new BasicFormat[alternateFormatList.size()]);
1385                format = new AlternateFormat(alternateFormats);
1386            }
1387        }
1388    
1389        /**
1390         * Constructs a <code>Format</code> in a specific locale, or retrieves
1391         * one from the cache if one already exists.
1392         *
1393         * <p>If the number of entries in the cache exceeds {@link #CacheLimit},
1394         * replaces the eldest entry in the cache.
1395         *
1396         * @param formatString the format string; see
1397         *   <a href="http://www.apostate.com/programming/vb-format.html">this
1398         *   description</a> for more details
1399         */
1400        public static Format get(String formatString, Locale locale) {
1401            String key = formatString + "@@@" + locale;
1402            Format format = (Format) cache.get(key);
1403            if (format == null) {
1404                synchronized (cache) {
1405                    format = (Format) cache.get(key);
1406                    if (format == null) {
1407                        format = new Format(formatString, locale);
1408                        cache.put(key, format);
1409                    }
1410                }
1411            }
1412            return format;
1413        }
1414    
1415        /**
1416         * Create a {@link FormatLocale} object characterized by the given
1417         * properties.
1418         *
1419         * @param thousandSeparator the character used to separate thousands in
1420         *   numbers, or ',' by default.  For example, 12345 is '12,345 in English,
1421         *   '12.345 in French.
1422         * @param decimalPlaceholder the character placed between the integer and
1423         *   the fractional part of decimal numbers, or '.' by default.  For
1424         *   example, 12.34 is '12.34' in English, '12,34' in French.
1425         * @param dateSeparator the character placed between the year, month and
1426         *   day of a date such as '12/07/2001', or '/' by default.
1427         * @param timeSeparator the character placed between the hour, minute and
1428         *   second value of a time such as '1:23:45 AM', or ':' by default.
1429         * @param daysOfWeekShort Short forms of the days of the week.
1430         *            The array is 1-based, because position
1431         *            {@link Calendar#SUNDAY} (= 1) must hold Sunday, etc.
1432         *            The array must have 8 elements.
1433         *            For example {"", "Sun", "Mon", ..., "Sat"}.
1434         * @param daysOfWeekLong Long forms of the days of the week.
1435         *            The array is 1-based, because position
1436         *            {@link Calendar#SUNDAY} must hold Sunday, etc.
1437         *            The array must have 8 elements.
1438         *            For example {"", "Sunday", ..., "Saturday"}.
1439         * @param monthsShort Short forms of the months of the year.
1440         *            The array is 0-based, because position
1441         *            {@link Calendar#JANUARY} (= 0) holds January, etc.
1442         *            For example {"Jan", ..., "Dec", ""}.
1443         * @param monthsLong Long forms of the months of the year.
1444         *            The array is 0-based, because position
1445         *            {@link Calendar#JANUARY} (= 0) holds January, etc.
1446         *            For example {"January", ..., "December", ""}.
1447         * @param locale if this is not null, register that the constructed
1448         *     <code>FormatLocale</code> is the default for <code>locale</code>
1449         */
1450        public static FormatLocale createLocale(
1451            char thousandSeparator,
1452            char decimalPlaceholder,
1453            String dateSeparator,
1454            String timeSeparator,
1455            String currencySymbol,
1456            String currencyFormat,
1457            String[] daysOfWeekShort,
1458            String[] daysOfWeekLong,
1459            String[] monthsShort,
1460            String[] monthsLong,
1461            Locale locale)
1462        {
1463            FormatLocale formatLocale = new FormatLocale(
1464                thousandSeparator, decimalPlaceholder, dateSeparator,
1465                timeSeparator, currencySymbol, currencyFormat, daysOfWeekShort,
1466                daysOfWeekLong, monthsShort, monthsLong, locale);
1467            if (locale != null) {
1468                registerFormatLocale(formatLocale, locale);
1469            }
1470            return formatLocale;
1471        }
1472    
1473        public static FormatLocale createLocale(Locale locale)
1474        {
1475            final DecimalFormatSymbols decimalSymbols =
1476                    new DecimalFormatSymbols(locale);
1477            final DateFormatSymbols dateSymbols = new DateFormatSymbols(locale);
1478    
1479            Calendar calendar = Calendar.getInstance(locale);
1480            calendar.set(1969, 11, 31, 0, 0, 0);
1481            final Date date = calendar.getTime();
1482    
1483            final java.text.DateFormat dateFormat =
1484                    java.text.DateFormat.getDateInstance(
1485                            java.text.DateFormat.SHORT, locale);
1486            final String dateValue = dateFormat.format(date); // "12/31/69"
1487            String dateSeparator = dateValue.substring(2, 3); // "/"
1488    
1489            final java.text.DateFormat timeFormat =
1490                    java.text.DateFormat.getTimeInstance(
1491                            java.text.DateFormat.SHORT, locale);
1492            final String timeValue = timeFormat.format(date); // "12:00:00"
1493            String timeSeparator = timeValue.substring(2, 3); // ":"
1494    
1495            // Deduce the locale's currency format.
1496            // For example, US is "$#,###.00"; France is "#,###-00FF".
1497            final NumberFormat currencyFormat =
1498                    NumberFormat.getCurrencyInstance(locale);
1499            final String currencyValue = currencyFormat.format(123456.78);
1500            String currencyLeft =
1501                    currencyValue.substring(0, currencyValue.indexOf("1"));
1502            String currencyRight =
1503                    currencyValue.substring(currencyValue.indexOf("8") + 1);
1504            StringBuilder buf = new StringBuilder();
1505            buf.append(currencyLeft);
1506            int minimumIntegerDigits = currencyFormat.getMinimumIntegerDigits();
1507            for (int i = Math.max(minimumIntegerDigits, 4) - 1; i >= 0; --i) {
1508                buf.append(i < minimumIntegerDigits ? '0' : '#');
1509                if (i % 3 == 0 && i > 0) {
1510                    buf.append(',');
1511                }
1512            }
1513            if (currencyFormat.getMaximumFractionDigits() > 0) {
1514                buf.append('.');
1515                appendTimes(buf, '0', currencyFormat.getMinimumFractionDigits());
1516                appendTimes(buf, '#',
1517                        currencyFormat.getMaximumFractionDigits() -
1518                        currencyFormat.getMinimumFractionDigits());
1519            }
1520            buf.append(currencyRight);
1521            String currencyFormatString = buf.toString();
1522    
1523            return createLocale(
1524                    decimalSymbols.getGroupingSeparator(),
1525                    decimalSymbols.getDecimalSeparator(),
1526                    dateSeparator,
1527                    timeSeparator,
1528                    decimalSymbols.getCurrencySymbol(),
1529                    currencyFormatString,
1530                    dateSymbols.getShortWeekdays(),
1531                    dateSymbols.getWeekdays(),
1532                    dateSymbols.getShortMonths(),
1533                    dateSymbols.getMonths(),
1534                    locale);
1535        }
1536    
1537        private static void appendTimes(StringBuilder buf, char c, int i) {
1538            while (i-- > 0) {
1539                buf.append(c);
1540            }
1541        }
1542    
1543        /**
1544         * Returns the {@link FormatLocale} which precisely matches {@link Locale},
1545         * if any, or null if there is none.
1546         */
1547        public static FormatLocale getFormatLocale(Locale locale)
1548        {
1549            if (locale == null) {
1550                locale = Locale.US;
1551            }
1552            String key = locale.toString();
1553            return mapLocaleToFormatLocale.get(key);
1554        }
1555    
1556        /**
1557         * Returns the best {@link FormatLocale} for a given {@link Locale}.
1558         * Never returns null, even if <code>locale</code> is null.
1559         */
1560        public static synchronized FormatLocale getBestFormatLocale(Locale locale)
1561        {
1562            FormatLocale formatLocale;
1563            if (locale == null) {
1564                return locale_US;
1565            }
1566            String key = locale.toString();
1567            // Look in the cache first.
1568            formatLocale = mapLocaleToFormatLocale.get(key);
1569            if (formatLocale == null) {
1570                // Not in the cache, so ask the factory.
1571                formatLocale = getFormatLocaleUsingFactory(locale);
1572                if (formatLocale == null) {
1573                    formatLocale = locale_US;
1574                }
1575                // Add to cache.
1576                mapLocaleToFormatLocale.put(key, formatLocale);
1577            }
1578            return formatLocale;
1579        }
1580    
1581        private static FormatLocale getFormatLocaleUsingFactory(Locale locale)
1582        {
1583            FormatLocale formatLocale;
1584            // Lookup full locale, e.g. "en-US-Boston"
1585            if (!locale.getVariant().equals("")) {
1586                formatLocale = createLocale(locale);
1587                if (formatLocale != null) {
1588                    return formatLocale;
1589                }
1590                locale = new Locale(locale.getLanguage(), locale.getCountry());
1591            }
1592            // Lookup language and country, e.g. "en-US"
1593            if (!locale.getCountry().equals("")) {
1594                formatLocale = createLocale(locale);
1595                if (formatLocale != null) {
1596                    return formatLocale;
1597                }
1598                locale = new Locale(locale.getLanguage());
1599            }
1600            // Lookup language, e.g. "en"
1601            formatLocale = createLocale(locale);
1602            if (formatLocale != null) {
1603                return formatLocale;
1604            }
1605            return null;
1606        }
1607    
1608        /**
1609         * Registers a {@link FormatLocale} to a given {@link Locale}. Returns the
1610         * previous mapping.
1611         */
1612        public static FormatLocale registerFormatLocale(
1613            FormatLocale formatLocale, Locale locale)
1614        {
1615            String key = locale.toString(); // e.g. "en_us_Boston"
1616            FormatLocale previous = mapLocaleToFormatLocale.put(key, formatLocale);
1617            return previous;
1618        }
1619    
1620        // Values for variable numberState below.
1621        static final int NOT_IN_A_NUMBER = 0;
1622        static final int LEFT_OF_POINT = 1;
1623        static final int RIGHT_OF_POINT = 2;
1624        static final int RIGHT_OF_EXP = 3;
1625    
1626        /**
1627         * Reads formatString up to the first semi-colon, or to the end if there
1628         * are no semi-colons.  Adds a format to alternateFormatList, and returns
1629         * the remains of formatString.
1630         */
1631        private String parseFormatString(
1632            String formatString, List<BasicFormat> alternateFormatList)
1633        {
1634            // Where we are in a numeric format.
1635            int numberState = NOT_IN_A_NUMBER;
1636            StringBuilder ignored = new StringBuilder();
1637            String prevIgnored = null;
1638            boolean haveSeenNumber = false;
1639            int digitsLeftOfPoint = 0,
1640                digitsRightOfPoint = 0,
1641                digitsRightOfExp = 0,
1642                zeroesLeftOfPoint = 0,
1643                zeroesRightOfPoint = 0,
1644                zeroesRightOfExp = 0;
1645            int stringCase = CASE_ASIS;
1646            boolean useDecimal = false,
1647                    useThouSep = false,
1648                    fillFromRight = true;
1649    
1650            /** Whether to print numbers in decimal or exponential format.  Valid
1651             * values are FORMAT_NULL, FORMAT_E_PLUS_LOWER, FORMAT_E_MINUS_LOWER,
1652             * FORMAT_E_PLUS_UPPER, FORMAT_E_MINUS_UPPER. */
1653            int expFormat = FORMAT_NULL;
1654    
1655            // todo: Parse the string for ;s
1656    
1657            // Look for the format string in the table of named formats.
1658            for (int i = 0; i < macroTokens.length; i++) {
1659                if (formatString.equals(macroTokens[i].name)) {
1660                    if (macroTokens[i].translation == null) {
1661                        // this macro requires special-case code
1662                        if (macroTokens[i].name.equals("Currency")) {
1663                            // e.g. "$#,##0.00;($#,##0.00)"
1664                            formatString = locale.currencyFormat
1665                                + ";("  + locale.currencyFormat + ")";
1666                        } else {
1667                            throw new Error(
1668                                "Format: internal: token " + macroTokens[i].name +
1669                                " should have translation");
1670                        }
1671                    } else {
1672                        formatString = macroTokens[i].translation;
1673                    }
1674                    break;
1675                }
1676            }
1677    
1678            // Add a semi-colon to the end of the string so the end of the string
1679            // looks like the end of an alternate.
1680            if (!formatString.endsWith(";")) {
1681                formatString = formatString + ";";
1682            }
1683    
1684            // Scan through the format string for format elements.
1685            List<BasicFormat> formatList = new ArrayList<BasicFormat>();
1686    loop:
1687            while (formatString.length() > 0) {
1688                BasicFormat format = null;
1689                String newFormatString = null;
1690                boolean ignoreToken = false;
1691                for (int i = tokens.length - 1; i > 0; i--) {
1692                    Token token = tokens[i];
1693                    if (formatString.startsWith(token.token)) {
1694                        // Derive the string we will be looking at next time
1695                        // around, by chewing the token off the front of the
1696                        // string.  Special-case code below can change this string,
1697                        // if it likes.
1698                        String matched = token.token;
1699                        newFormatString = formatString.substring(matched.length());
1700                        if (token.isSpecial()) {
1701                            switch (token.code) {
1702                            case FORMAT_SEMI:
1703                                formatString = newFormatString;
1704                                break loop;
1705    
1706                            case FORMAT_POUND:
1707                                switch (numberState) {
1708                                case NOT_IN_A_NUMBER:
1709                                    numberState = LEFT_OF_POINT;
1710                                    // fall through
1711                                case LEFT_OF_POINT:
1712                                    digitsLeftOfPoint++;
1713                                    break;
1714                                case RIGHT_OF_POINT:
1715                                    digitsRightOfPoint++;
1716                                    break;
1717                                case RIGHT_OF_EXP:
1718                                    digitsRightOfExp++;
1719                                    break;
1720                                default:
1721                                    throw new Error();
1722                                }
1723                                break;
1724    
1725                            case FORMAT_0:
1726                                switch (numberState) {
1727                                case NOT_IN_A_NUMBER:
1728                                    numberState = LEFT_OF_POINT;
1729                                    // fall through
1730                                case LEFT_OF_POINT:
1731                                    zeroesLeftOfPoint++;
1732                                    break;
1733                                case RIGHT_OF_POINT:
1734                                    zeroesRightOfPoint++;
1735                                    break;
1736                                case RIGHT_OF_EXP:
1737                                    zeroesRightOfExp++;
1738                                    break;
1739                                default:
1740                                    throw new Error();
1741                                }
1742                                break;
1743    
1744                            case FORMAT_M:
1745                            case FORMAT_MM:
1746                            {
1747                                // "m" and "mm" mean minute if immediately after
1748                                // "h" or "hh"; month otherwise.
1749                                boolean theyMeantMinute = false;
1750                                int j = formatList.size() - 1;
1751                                while (j >= 0) {
1752                                    BasicFormat prevFormat = formatList.get(j);
1753                                    if (prevFormat instanceof LiteralFormat) {
1754                                        // ignore boilerplate
1755                                        j--;
1756                                    } else if (prevFormat.code == FORMAT_H ||
1757                                               prevFormat.code == FORMAT_HH) {
1758                                        theyMeantMinute = true;
1759                                        break;
1760                                    } else {
1761                                        theyMeantMinute = false;
1762                                        break;
1763                                    }
1764                                }
1765                                if (theyMeantMinute) {
1766                                    format = new DateFormat(
1767                                        (token.code == FORMAT_M
1768                                         ? FORMAT_N
1769                                         : FORMAT_NN),
1770                                        matched,
1771                                        locale,
1772                                        false);
1773                                } else {
1774                                    format = token.makeFormat(locale);
1775                                }
1776                                break;
1777                            }
1778    
1779                            case FORMAT_DECIMAL:
1780                            {
1781                                numberState = RIGHT_OF_POINT;
1782                                useDecimal = true;
1783                                break;
1784                            }
1785    
1786                            case FORMAT_THOUSEP:
1787                            {
1788                                if (numberState == LEFT_OF_POINT) {
1789                                    // e.g. "#,##"
1790                                    useThouSep = true;
1791                                } else {
1792                                    // e.g. "ddd, mmm dd, yyy"
1793                                    format = token.makeFormat(locale);
1794                                }
1795                                break;
1796                            }
1797    
1798                            case FORMAT_TIMESEP:
1799                            {
1800                                format = new LiteralFormat(locale.timeSeparator);
1801                                break;
1802                            }
1803    
1804                            case FORMAT_DATESEP:
1805                            {
1806                                format = new LiteralFormat(locale.dateSeparator);
1807                                break;
1808                            }
1809    
1810                            case FORMAT_BACKSLASH:
1811                            {
1812                                // Display the next character in the format string.
1813                                String s = "";
1814                                if (formatString.length() == 1) {
1815                                    // Backslash is the last character in the
1816                                    // string.
1817                                    s = "";
1818                                    newFormatString = "";
1819                                } else {
1820                                    s = formatString.substring(1,2);
1821                                    newFormatString = formatString.substring(2);
1822                                }
1823                                format = new LiteralFormat(s);
1824                                break;
1825                            }
1826    
1827                            case FORMAT_E_MINUS_UPPER:
1828                            case FORMAT_E_PLUS_UPPER:
1829                            case FORMAT_E_MINUS_LOWER:
1830                            case FORMAT_E_PLUS_LOWER:
1831                            {
1832                                numberState = RIGHT_OF_EXP;
1833                                expFormat = token.code;
1834                                if (zeroesLeftOfPoint == 0 &&
1835                                    zeroesRightOfPoint == 0) {
1836                                    // We need a mantissa, so that format(123.45,
1837                                    // "E+") gives "1E+2", not "0E+2" or "E+2".
1838                                    zeroesLeftOfPoint = 1;
1839                                }
1840                                break;
1841                            }
1842    
1843                            case FORMAT_QUOTE:
1844                            {
1845                                // Display the string inside the double quotation
1846                                // marks.
1847                                String s;
1848                                int j = formatString.indexOf("\"", 1);
1849                                if (j == -1) {
1850                                    // The string did not contain a closing quote.
1851                                    // Use the whole string.
1852                                    s = formatString.substring(1);
1853                                    newFormatString = "";
1854                                } else {
1855                                    // Take the string inside the quotes.
1856                                    s = formatString.substring(1, j);
1857                                    newFormatString = formatString.substring(
1858                                        j + 1);
1859                                }
1860                                format = new LiteralFormat(s);
1861                                break;
1862                            }
1863    
1864                            case FORMAT_UPPER:
1865                            {
1866                                stringCase = CASE_UPPER;
1867                                break;
1868                            }
1869    
1870                            case FORMAT_LOWER:
1871                            {
1872                                stringCase = CASE_LOWER;
1873                                break;
1874                            }
1875    
1876                            case FORMAT_FILL_FROM_LEFT:
1877                            {
1878                                fillFromRight = false;
1879                                break;
1880                            }
1881    
1882                            case FORMAT_GENERAL_NUMBER:
1883                            {
1884                                format = new JavaFormat(locale.locale);
1885                                break;
1886                            }
1887    
1888                            case FORMAT_GENERAL_DATE:
1889                            {
1890                                format = new JavaFormat(locale.locale);
1891                                break;
1892                            }
1893    
1894                            case FORMAT_INTL_CURRENCY:
1895                            {
1896                                format = new LiteralFormat(locale.currencySymbol);
1897                                break;
1898                            }
1899    
1900                            default:
1901                                throw new Error();
1902                            }
1903                            if (format == null) {
1904                                // If the special-case code does not set format,
1905                                // we should not create a format element.  (The
1906                                // token probably caused some flag to be set.)
1907                                ignoreToken = true;
1908                                ignored.append(matched);
1909                            } else {
1910                                prevIgnored = ignored.toString();
1911                                ignored.setLength(0);
1912                            }
1913                        } else {
1914                            format = token.makeFormat(locale);
1915                        }
1916                        break;
1917                    }
1918                }
1919    
1920                if (format == null && !ignoreToken) {
1921                    // None of the standard format elements matched.  Make the
1922                    // current character into a literal.
1923                    format = new LiteralFormat(
1924                        formatString.substring(0,1));
1925                    newFormatString = formatString.substring(1);
1926                }
1927    
1928                if (format != null) {
1929                    if (numberState != NOT_IN_A_NUMBER) {
1930                        // Having seen a few number tokens, we're looking at a
1931                        // non-number token.  Create the number first.
1932                        NumericFormat numericFormat = new NumericFormat(
1933                            prevIgnored, locale, expFormat, digitsLeftOfPoint,
1934                            zeroesLeftOfPoint, digitsRightOfPoint,
1935                            zeroesRightOfPoint, digitsRightOfExp, zeroesRightOfExp,
1936                            useDecimal, useThouSep);
1937                        formatList.add(numericFormat);
1938                        numberState = NOT_IN_A_NUMBER;
1939                        haveSeenNumber = true;
1940                    }
1941    
1942                    formatList.add(format);
1943                }
1944    
1945                formatString = newFormatString;
1946            }
1947    
1948            if (numberState != NOT_IN_A_NUMBER) {
1949                // We're still in a number.  Create a number format.
1950                NumericFormat numericFormat = new NumericFormat(
1951                    prevIgnored, locale, expFormat, digitsLeftOfPoint,
1952                    zeroesLeftOfPoint, digitsRightOfPoint, zeroesRightOfPoint,
1953                    digitsRightOfExp, zeroesRightOfExp, useDecimal, useThouSep);
1954                formatList.add(numericFormat);
1955                numberState = NOT_IN_A_NUMBER;
1956                haveSeenNumber = true;
1957            }
1958    
1959            // The is the end of an alternate - or of the whole format string.
1960            // Push the current list of formats onto the list of alternates.
1961            BasicFormat[] formats =
1962                formatList.toArray(new BasicFormat[formatList.size()]);
1963    
1964            // If they used some symbol like 'AM/PM' in the format string, tell all
1965            // date formats to use twelve hour clock.  Likewise, figure out the
1966            // multiplier implied by their use of "%" or ",".
1967            boolean twelveHourClock = false;
1968            int decimalShift = 0;
1969            for (int i = 0; i < formats.length; i++) {
1970                switch (formats[i].code) {
1971                case FORMAT_UPPER_AM_SOLIDUS_PM:
1972                case FORMAT_LOWER_AM_SOLIDUS_PM:
1973                case FORMAT_UPPER_A_SOLIDUS_P:
1974                case FORMAT_LOWER_A_SOLIDUS_P:
1975                case FORMAT_AMPM:
1976                    twelveHourClock = true;
1977                    break;
1978    
1979                case FORMAT_PERCENT:
1980                    // If "%" occurs, the number should be multiplied by 100.
1981                    decimalShift += 2;
1982                    break;
1983    
1984                case FORMAT_THOUSEP:
1985                    // If there is a thousands separator (",") immediately to the
1986                    // left of the point, or at the end of the number, divide the
1987                    // number by 1000.  (Or by 1000^n if there are more than one.)
1988                    if (haveSeenNumber &&
1989                        i + 1 < formats.length &&
1990                        formats[i + 1].code != FORMAT_THOUSEP &&
1991                        formats[i + 1].code != FORMAT_0 &&
1992                        formats[i + 1].code != FORMAT_POUND) {
1993                        for (int j = i;
1994                             j >= 0 && formats[j].code == FORMAT_THOUSEP;
1995                             j--) {
1996                            decimalShift -= 3;
1997                            formats[j] = new LiteralFormat(""); // ignore
1998                        }
1999                    }
2000                    break;
2001    
2002                default:
2003                }
2004            }
2005    
2006            if (twelveHourClock) {
2007                for (int i = 0; i < formats.length; i++) {
2008                    if (formats[i] instanceof DateFormat) {
2009                        ((DateFormat) formats[i]).setTwelveHourClock(true);
2010                    }
2011                }
2012            }
2013    
2014            if (decimalShift != 0) {
2015                for (int i = 0; i < formats.length; i++) {
2016                    if (formats[i] instanceof NumericFormat) {
2017                        ((NumericFormat) formats[i]).decimalShift = decimalShift;
2018                    }
2019                }
2020            }
2021    
2022            // Create a CompoundFormat containing all of the format elements.
2023            BasicFormat alternateFormat =
2024                    formats.length == 0 ? null :
2025                    formats.length == 1 ? formats[0] :
2026                    new CompoundFormat(formats);
2027            alternateFormatList.add(alternateFormat);
2028            return formatString;
2029        }
2030    
2031        public String format(Object o)
2032        {
2033            StringBuilder buf = new StringBuilder();
2034            format(o, buf);
2035            return buf.toString();
2036        }
2037    
2038        private StringBuilder format(Object o, StringBuilder buf) {
2039            if (o == null) {
2040                format.formatNull(buf);
2041            } else {
2042                // For final classes, it is more efficient to switch using
2043                // class equality than using 'instanceof'.
2044                Class<? extends Object> clazz = o.getClass();
2045                if (clazz == Double.class) {
2046                    format.format(((Double) o).doubleValue(), buf);
2047                } else if (clazz == Float.class) {
2048                    format.format(((Float) o).floatValue(), buf);
2049                } else if (clazz == Integer.class) {
2050                    format.format(((Integer) o).intValue(), buf);
2051                } else if (clazz == Long.class) {
2052                    format.format(((Long) o).longValue(), buf);
2053                } else if (clazz == Short.class) {
2054                    format.format(((Short) o).shortValue(), buf);
2055                } else if (clazz == Byte.class) {
2056                    format.format(((Byte) o).byteValue(), buf);
2057                } else if (o instanceof BigDecimal) {
2058                    format.format(((BigDecimal) o).doubleValue(), buf);
2059                } else if (o instanceof BigInteger) {
2060                    format.format(((BigInteger) o).longValue(), buf);
2061                } else if (clazz == String.class) {
2062                    format.format((String) o, buf);
2063                } else if (o instanceof java.util.Date) {
2064                    // includes java.sql.Date, java.sql.Time and java.sql.Timestamp
2065                    format.format((Date) o, buf);
2066                } else {
2067                    buf.append(o.toString());
2068                }
2069            }
2070            return buf;
2071        }
2072    
2073        public String getFormatString()
2074        {
2075            return formatString;
2076        }
2077    
2078        /**
2079         * Locates a {@link Format.FormatLocale} for a given locale.
2080         */
2081        public interface LocaleFormatFactory {
2082            FormatLocale get(Locale locale);
2083        }
2084    
2085        private static class DummyDecimalFormat extends DecimalFormat {
2086            private FieldPosition pos;
2087    
2088            public StringBuffer format(
2089                    double number,
2090                    StringBuffer result,
2091                    FieldPosition fieldPosition) {
2092                pos = fieldPosition;
2093                return result;
2094            }
2095        }
2096    
2097    /**
2098     * Copied from <code>java.lang.FloatingDecimal</code>.
2099     */
2100    static class FloatingDecimal {
2101        boolean     isExceptional;
2102        boolean     isNegative;
2103        int         decExponent;
2104        char        digits[];
2105        int         nDigits;
2106    
2107        /*
2108         * Constants of the implementation
2109         * Most are IEEE-754 related.
2110         * (There are more really boring constants at the end.)
2111         */
2112        static final long   signMask = 0x8000000000000000L;
2113        static final long   expMask  = 0x7ff0000000000000L;
2114        static final long   fractMask = ~(signMask | expMask);
2115        static final int    expShift = 52;
2116        static final int    expBias  = 1023;
2117        static final long   fractHOB = (1L<<expShift); // assumed High-Order bit
2118        static final long   expOne   = ((long)expBias)<<expShift; // exponent of 1.0
2119        static final int    maxSmallBinExp = 62;
2120        static final int    minSmallBinExp = -(63 / 3);
2121    
2122        static final long   highbyte = 0xff00000000000000L;
2123        static final long   highbit  = 0x8000000000000000L;
2124        static final long   lowbytes = ~highbyte;
2125    
2126        static final int    singleSignMask =    0x80000000;
2127        static final int    singleExpMask  =    0x7f800000;
2128        static final int    singleFractMask =   ~(singleSignMask | singleExpMask);
2129        static final int    singleExpShift  =   23;
2130        static final int    singleFractHOB  =   1<<singleExpShift;
2131        static final int    singleExpBias   =   127;
2132    
2133        /*
2134         * count number of bits from high-order 1 bit to low-order 1 bit,
2135         * inclusive.
2136         */
2137        private static int
2138        countBits(long v) {
2139            //
2140            // the strategy is to shift until we get a non-zero sign bit
2141            // then shift until we have no bits left, counting the difference.
2142            // we do byte shifting as a hack. Hope it helps.
2143            //
2144            if (v == 0L) {
2145                return 0;
2146            }
2147    
2148            while ((v & highbyte) == 0L) {
2149                v <<= 8;
2150            }
2151            while (v > 0L) { // i.e. while ((v&highbit) == 0L )
2152                v <<= 1;
2153            }
2154    
2155            int n = 0;
2156            while ((v & lowbytes) != 0L) {
2157                v <<= 8;
2158                n += 8;
2159            }
2160            while (v != 0L) {
2161                v <<= 1;
2162                n += 1;
2163            }
2164            return n;
2165        }
2166    
2167        /*
2168         * Keep big powers of 5 handy for future reference.
2169         */
2170        private static FDBigInt b5p[];
2171    
2172        private static FDBigInt
2173        big5pow(int p) {
2174            if (p < 0)
2175                throw new RuntimeException("Assertion botch: negative power of 5");
2176            if (b5p == null) {
2177                b5p = new FDBigInt[p + 1];
2178            } else if (b5p.length <= p) {
2179                FDBigInt t[] = new FDBigInt[p + 1];
2180                System.arraycopy(b5p, 0, t, 0, b5p.length);
2181                b5p = t;
2182            }
2183            if (b5p[p] != null) {
2184                return b5p[p];
2185            } else if (p < small5pow.length) {
2186                return b5p[p] = new FDBigInt(small5pow[p]);
2187            } else if (p < long5pow.length) {
2188                return b5p[p] = new FDBigInt(long5pow[p]);
2189            } else {
2190                // construct the damn thing.
2191                // recursively.
2192                int q, r;
2193                // in order to compute 5^p,
2194                // compute its square root, 5^(p/2) and square.
2195                // or, let q = p / 2, r = p -q, then
2196                // 5^p = 5^(q+r) = 5^q * 5^r
2197                q = p >> 1;
2198                r = p - q;
2199                FDBigInt bigq =  b5p[q];
2200                if (bigq == null)
2201                    bigq = big5pow (q);
2202                if (r < small5pow.length) {
2203                    return (b5p[p] = bigq.mult(small5pow[r]));
2204                } else {
2205                    FDBigInt bigr = b5p[r];
2206                    if (bigr == null)
2207                        bigr = big5pow(r);
2208                    return (b5p[p] = bigq.mult(bigr));
2209                }
2210            }
2211        }
2212    
2213        /*
2214         * This is the easy subcase --
2215         * all the significant bits, after scaling, are held in lvalue.
2216         * negSign and decExponent tell us what processing and scaling
2217         * has already been done. Exceptional cases have already been
2218         * stripped out.
2219         * In particular:
2220         * lvalue is a finite number (not Inf, nor NaN)
2221         * lvalue > 0L (not zero, nor negative).
2222         *
2223         * The only reason that we develop the digits here, rather than
2224         * calling on Long.toString() is that we can do it a little faster,
2225         * and besides want to treat trailing 0s specially. If Long.toString
2226         * changes, we should re-evaluate this strategy!
2227         */
2228        private void
2229        developLongDigits(int decExponent, long lvalue, long insignificant) {
2230            char digits[];
2231            int  ndigits;
2232            int  digitno;
2233            int  c;
2234            //
2235            // Discard non-significant low-order bits, while rounding,
2236            // up to insignificant value.
2237            int i;
2238            for (i = 0; insignificant >= 10L; i++)
2239                insignificant /= 10L;
2240            if (i != 0) {
2241                long pow10 = long5pow[i] << i; // 10^i == 5^i * 2^i;
2242                long residue = lvalue % pow10;
2243                lvalue /= pow10;
2244                decExponent += i;
2245                if (residue >= (pow10>>1)) {
2246                    // round up based on the low-order bits we're discarding
2247                    lvalue++;
2248                }
2249            }
2250            if (lvalue <= Integer.MAX_VALUE) {
2251                if (lvalue <= 0L)
2252                    throw new RuntimeException("Assertion botch: value " + lvalue + " <= 0");
2253    
2254                // even easier subcase!
2255                // can do int arithmetic rather than long!
2256                int  ivalue = (int)lvalue;
2257                digits = new char[ndigits = 10];
2258                digitno = ndigits - 1;
2259                c = ivalue % 10;
2260                ivalue /= 10;
2261                while (c == 0) {
2262                    decExponent++;
2263                    c = ivalue % 10;
2264                    ivalue /= 10;
2265                }
2266                while (ivalue != 0) {
2267                    digits[digitno--] = (char)(c + '0');
2268                    decExponent++;
2269                    c = ivalue % 10;
2270                    ivalue /= 10;
2271                }
2272                digits[digitno] = (char)(c + '0');
2273            } else {
2274                // same algorithm as above (same bugs, too)
2275                // but using long arithmetic.
2276                digits = new char[ndigits = 20];
2277                digitno = ndigits - 1;
2278                c = (int)(lvalue % 10L);
2279                lvalue /= 10L;
2280                while (c == 0) {
2281                    decExponent++;
2282                    c = (int)(lvalue % 10L);
2283                    lvalue /= 10L;
2284                }
2285                while (lvalue != 0L) {
2286                    digits[digitno--] = (char)(c + '0');
2287                    decExponent++;
2288                    c = (int)(lvalue % 10L);
2289                    lvalue /= 10;
2290                }
2291                digits[digitno] = (char)(c + '0');
2292            }
2293            char result [];
2294            ndigits -= digitno;
2295            if (digitno == 0) {
2296                result = digits;
2297            } else {
2298                result = new char[ndigits];
2299                System.arraycopy(digits, digitno, result, 0, ndigits);
2300            }
2301            this.digits = result;
2302            this.decExponent = decExponent + 1;
2303            this.nDigits = ndigits;
2304        }
2305    
2306        //
2307        // add one to the least significant digit.
2308        // in the unlikely event there is a carry out,
2309        // deal with it.
2310        // assert that this will only happen where there
2311        // is only one digit, e.g. (float)1e-44 seems to do it.
2312        //
2313        private void
2314        roundup() {
2315            int i;
2316            int q = digits[i = (nDigits - 1)];
2317            if (q == '9') {
2318                while (q == '9' && i > 0) {
2319                    digits[i] = '0';
2320                    q = digits[--i];
2321                }
2322                if (q == '9') {
2323                    // carryout! High-order 1, rest 0s, larger exp.
2324                    decExponent += 1;
2325                    digits[0] = '1';
2326                    return;
2327                }
2328                // else fall through.
2329            }
2330            digits[i] = (char)(q + 1);
2331        }
2332    
2333        /*
2334         * FIRST IMPORTANT CONSTRUCTOR: DOUBLE
2335         */
2336        public FloatingDecimal(double d)
2337        {
2338            long    dBits = Double.doubleToLongBits(d);
2339            long    fractBits;
2340            int     binExp;
2341            int     nSignificantBits;
2342    
2343            // discover and delete sign
2344            if ((dBits & signMask) != 0) {
2345                isNegative = true;
2346                dBits ^= signMask;
2347            } else {
2348                isNegative = false;
2349            }
2350            // Begin to unpack
2351            // Discover obvious special cases of NaN and Infinity.
2352            binExp = (int)((dBits & expMask) >> expShift);
2353            fractBits = dBits & fractMask;
2354            if (binExp == (int)(expMask>>expShift)) {
2355                isExceptional = true;
2356                if (fractBits == 0L) {
2357                    digits =  infinity;
2358                } else {
2359                    digits = notANumber;
2360                    isNegative = false; // NaN has no sign!
2361                }
2362                nDigits = digits.length;
2363                return;
2364            }
2365            isExceptional = false;
2366            // Finish unpacking
2367            // Normalize denormalized numbers.
2368            // Insert assumed high-order bit for normalized numbers.
2369            // Subtract exponent bias.
2370            if (binExp == 0) {
2371                if (fractBits == 0L) {
2372                    // not a denorm, just a 0!
2373                    decExponent = 0;
2374                    digits = zero;
2375                    nDigits = 1;
2376                    return;
2377                }
2378                while ((fractBits & fractHOB) == 0L) {
2379                    fractBits <<= 1;
2380                    binExp -= 1;
2381                }
2382                nSignificantBits = expShift + binExp; // recall binExp is  - shift count.
2383                binExp += 1;
2384            } else {
2385                fractBits |= fractHOB;
2386                nSignificantBits = expShift + 1;
2387            }
2388            binExp -= expBias;
2389            // call the routine that actually does all the hard work.
2390            dtoa(binExp, fractBits, nSignificantBits);
2391        }
2392    
2393        /*
2394         * SECOND IMPORTANT CONSTRUCTOR: SINGLE
2395         */
2396        public FloatingDecimal(float f)
2397        {
2398            int     fBits = Float.floatToIntBits(f);
2399            int     fractBits;
2400            int     binExp;
2401            int     nSignificantBits;
2402    
2403            // discover and delete sign
2404            if ((fBits & singleSignMask) != 0) {
2405                isNegative = true;
2406                fBits ^= singleSignMask;
2407            } else {
2408                isNegative = false;
2409            }
2410            // Begin to unpack
2411            // Discover obvious special cases of NaN and Infinity.
2412            binExp = ((fBits & singleExpMask) >> singleExpShift);
2413            fractBits = fBits & singleFractMask;
2414            if (binExp == (singleExpMask>>singleExpShift)) {
2415                isExceptional = true;
2416                if (fractBits == 0L) {
2417                    digits =  infinity;
2418                } else {
2419                    digits = notANumber;
2420                    isNegative = false; // NaN has no sign!
2421                }
2422                nDigits = digits.length;
2423                return;
2424            }
2425            isExceptional = false;
2426            // Finish unpacking
2427            // Normalize denormalized numbers.
2428            // Insert assumed high-order bit for normalized numbers.
2429            // Subtract exponent bias.
2430            if (binExp == 0) {
2431                if (fractBits == 0) {
2432                    // not a denorm, just a 0!
2433                    decExponent = 0;
2434                    digits = zero;
2435                    nDigits = 1;
2436                    return;
2437                }
2438                while ((fractBits & singleFractHOB) == 0) {
2439                    fractBits <<= 1;
2440                    binExp -= 1;
2441                }
2442                nSignificantBits = singleExpShift + binExp; // recall binExp is  - shift count.
2443                binExp += 1;
2444            } else {
2445                fractBits |= singleFractHOB;
2446                nSignificantBits = singleExpShift + 1;
2447            }
2448            binExp -= singleExpBias;
2449            // call the routine that actually does all the hard work.
2450            dtoa(binExp, ((long)fractBits)<<(expShift - singleExpShift), nSignificantBits);
2451        }
2452    
2453        private void
2454        dtoa(int binExp, long fractBits, int nSignificantBits)
2455        {
2456            int     nFractBits; // number of significant bits of fractBits;
2457            int     nTinyBits;  // number of these to the right of the point.
2458            int     decExp;
2459    
2460            // Examine number. Determine if it is an easy case,
2461            // which we can do pretty trivially using float/long conversion,
2462            // or whether we must do real work.
2463            nFractBits = countBits(fractBits);
2464            nTinyBits = Math.max(0, nFractBits - binExp - 1);
2465            if (binExp <= maxSmallBinExp && binExp >= minSmallBinExp) {
2466                // Look more closely at the number to decide if,
2467                // with scaling by 10^nTinyBits, the result will fit in
2468                // a long.
2469                if ((nTinyBits < long5pow.length) && ((nFractBits + n5bits[nTinyBits]) < 64)) {
2470                    /*
2471                     * We can do this:
2472                     * take the fraction bits, which are normalized.
2473                     * (a) nTinyBits == 0: Shift left or right appropriately
2474                     *     to align the binary point at the extreme right, i.e.
2475                     *     where a long int point is expected to be. The integer
2476                     *     result is easily converted to a string.
2477                     * (b) nTinyBits > 0: Shift right by expShift-nFractBits,
2478                     *     which effectively converts to long and scales by
2479                     *     2^nTinyBits. Then multiply by 5^nTinyBits to
2480                     *     complete the scaling. We know this won't overflow
2481                     *     because we just counted the number of bits necessary
2482                     *     in the result. The integer you get from this can
2483                     *     then be converted to a string pretty easily.
2484                     */
2485                    long halfULP;
2486                    if (nTinyBits == 0) {
2487                        if (binExp > nSignificantBits) {
2488                            halfULP = 1L << (binExp - nSignificantBits - 1);
2489                        } else {
2490                            halfULP = 0L;
2491                        }
2492                        if (binExp >= expShift) {
2493                            fractBits <<= (binExp - expShift);
2494                        } else {
2495                            fractBits >>>= (expShift - binExp);
2496                        }
2497                        developLongDigits(0, fractBits, halfULP);
2498                        return;
2499                    }
2500                    /*
2501                     * The following causes excess digits to be printed
2502                     * out in the single-float case. Our manipulation of
2503                     * halfULP here is apparently not correct. If we
2504                     * better understand how this works, perhaps we can
2505                     * use this special case again. But for the time being,
2506                     * we do not.
2507                     * else {
2508                     *     fractBits >>>= expShift + 1-nFractBits;
2509                     *     fractBits *= long5pow[ nTinyBits ];
2510                     *     halfULP = long5pow[ nTinyBits ] >> (1+nSignificantBits-nFractBits);
2511                     *     developLongDigits(-nTinyBits, fractBits, halfULP);
2512                     *     return;
2513                     * }
2514                     */
2515                }
2516            }
2517            /*
2518             * This is the hard case. We are going to compute large positive
2519             * integers B and S and integer decExp, s.t.
2520             *      d = (B / S) * 10^decExp
2521             *      1 <= B / S < 10
2522             * Obvious choices are:
2523             *      decExp = floor(log10(d))
2524             *      B      = d * 2^nTinyBits * 10^max(0, -decExp)
2525             *      S      = 10^max(0, decExp) * 2^nTinyBits
2526             * (noting that nTinyBits has already been forced to non-negative)
2527             * I am also going to compute a large positive integer
2528             *      M      = (1/2^nSignificantBits) * 2^nTinyBits * 10^max(0, -decExp)
2529             * i.e. M is (1/2) of the ULP of d, scaled like B.
2530             * When we iterate through dividing B/S and picking off the
2531             * quotient bits, we will know when to stop when the remainder
2532             * is <= M.
2533             *
2534             * We keep track of powers of 2 and powers of 5.
2535             */
2536    
2537            /*
2538             * Estimate decimal exponent. (If it is small-ish,
2539             * we could double-check.)
2540             *
2541             * First, scale the mantissa bits such that 1 <= d2 < 2.
2542             * We are then going to estimate
2543             *          log10(d2) ~=~  (d2-1.5)/1.5 + log(1.5)
2544             * and so we can estimate
2545             *      log10(d) ~=~ log10(d2) + binExp * log10(2)
2546             * take the floor and call it decExp.
2547             * FIXME -- use more precise constants here. It costs no more.
2548             */
2549            double d2 = Double.longBitsToDouble(
2550                expOne | (fractBits &~ fractHOB));
2551            decExp = (int)Math.floor(
2552                (d2 - 1.5D) * 0.289529654D + 0.176091259 + (double)binExp * 0.301029995663981);
2553            int B2, B5; // powers of 2 and powers of 5, respectively, in B
2554            int S2, S5; // powers of 2 and powers of 5, respectively, in S
2555            int M2, M5; // powers of 2 and powers of 5, respectively, in M
2556            int Bbits; // binary digits needed to represent B, approx.
2557            int tenSbits; // binary digits needed to represent 10*S, approx.
2558            FDBigInt Sval, Bval, Mval;
2559    
2560            B5 = Math.max(0, -decExp);
2561            B2 = B5 + nTinyBits + binExp;
2562    
2563            S5 = Math.max(0, decExp);
2564            S2 = S5 + nTinyBits;
2565    
2566            M5 = B5;
2567            M2 = B2 - nSignificantBits;
2568    
2569            /*
2570             * the long integer fractBits contains the (nFractBits) interesting
2571             * bits from the mantissa of d (hidden 1 added if necessary) followed
2572             * by (expShift + 1-nFractBits) zeros. In the interest of compactness,
2573             * I will shift out those zeros before turning fractBits into a
2574             * FDBigInt. The resulting whole number will be
2575             *      d * 2^(nFractBits-1-binExp).
2576             */
2577            fractBits >>>= (expShift + 1 - nFractBits);
2578            B2 -= nFractBits - 1;
2579            int common2factor = Math.min(B2, S2);
2580            B2 -= common2factor;
2581            S2 -= common2factor;
2582            M2 -= common2factor;
2583    
2584            /*
2585             * HACK!! For exact powers of two, the next smallest number
2586             * is only half as far away as we think (because the meaning of
2587             * ULP changes at power-of-two bounds) for this reason, we
2588             * hack M2. Hope this works.
2589             */
2590            if (nFractBits == 1)
2591                M2 -= 1;
2592    
2593            if (M2 < 0) {
2594                // oops.
2595                // since we cannot scale M down far enough,
2596                // we must scale the other values up.
2597                B2 -= M2;
2598                S2 -= M2;
2599                M2 =  0;
2600            }
2601            /*
2602             * Construct, Scale, iterate.
2603             * Some day, we'll write a stopping test that takes
2604             * account of the assymetry of the spacing of floating-point
2605             * numbers below perfect powers of 2
2606             * 26 Sept 96 is not that day.
2607             * So we use a symmetric test.
2608             */
2609            char digits[] = this.digits = new char[18];
2610            int  ndigit = 0;
2611            boolean low, high;
2612            long lowDigitDifference;
2613            int  q;
2614    
2615            /*
2616             * Detect the special cases where all the numbers we are about
2617             * to compute will fit in int or long integers.
2618             * In these cases, we will avoid doing FDBigInt arithmetic.
2619             * We use the same algorithms, except that we "normalize"
2620             * our FDBigInts before iterating. This is to make division easier,
2621             * as it makes our fist guess (quotient of high-order words)
2622             * more accurate!
2623             *
2624             * Some day, we'll write a stopping test that takes
2625             * account of the assymetry of the spacing of floating-point
2626             * numbers below perfect powers of 2
2627             * 26 Sept 96 is not that day.
2628             * So we use a symmetric test.
2629             */
2630            Bbits = nFractBits + B2 + ((B5 < n5bits.length) ? n5bits[B5] : (B5 * 3));
2631            tenSbits = S2 + 1 + (((S5 + 1) < n5bits.length) ? n5bits[(S5 + 1)] : ((S5 + 1) * 3));
2632            if (Bbits < 64 && tenSbits < 64) {
2633                if (Bbits < 32 && tenSbits < 32) {
2634                    // wa-hoo! They're all ints!
2635                    int b = ((int)fractBits * small5pow[B5]) << B2;
2636                    int s = small5pow[S5] << S2;
2637                    int m = small5pow[M5] << M2;
2638                    int tens = s * 10;
2639                    /*
2640                     * Unroll the first iteration. If our decExp estimate
2641                     * was too high, our first quotient will be zero. In this
2642                     * case, we discard it and decrement decExp.
2643                     */
2644                    ndigit = 0;
2645                    q = (b / s);
2646                    b = 10 * (b % s);
2647                    m *= 10;
2648                    low  = (b <  m);
2649                    high = (b + m > tens);
2650                    if (q >= 10) {
2651                        // bummer, dude
2652                        throw new RuntimeException("Assertion botch: excessivly large digit " + q);
2653                    } else if ((q == 0) && ! high) {
2654                        // oops. Usually ignore leading zero.
2655                        decExp--;
2656                    } else {
2657                        digits[ndigit++] = (char)('0' + q);
2658                    }
2659                    /*
2660                     * HACK! Java spec sez that we always have at least
2661                     * one digit after the . in either F- or E-form output.
2662                     * Thus we will need more than one digit if we're using
2663                     * E-form
2664                     */
2665                    if (decExp <= -3 || decExp >= 8) {
2666                        high = low = false;
2667                    }
2668                    while (! low && ! high) {
2669                        q = (b / s);
2670                        b = 10 * (b % s);
2671                        m *= 10;
2672                        if (q >= 10) {
2673                            // bummer, dude
2674                            throw new RuntimeException("Assertion botch: excessivly large digit " + q);
2675                        }
2676                        if (m > 0L) {
2677                            low  = (b <  m);
2678                            high = (b + m > tens);
2679                        } else {
2680                            // hack -- m might overflow!
2681                            // in this case, it is certainly > b,
2682                            // which won't
2683                            // and b+m > tens, too, since that has overflowed
2684                            // either!
2685                            low = true;
2686                            high = true;
2687                        }
2688                        digits[ndigit++] = (char)('0' + q);
2689                    }
2690                    lowDigitDifference = (b<<1) - tens;
2691                } else {
2692                    // still good! they're all longs!
2693                    long b = (fractBits * long5pow[B5]) << B2;
2694                    long s = long5pow[S5] << S2;
2695                    long m = long5pow[M5] << M2;
2696                    long tens = s * 10L;
2697                    /*
2698                     * Unroll the first iteration. If our decExp estimate
2699                     * was too high, our first quotient will be zero. In this
2700                     * case, we discard it and decrement decExp.
2701                     */
2702                    ndigit = 0;
2703                    q = (int) (b / s);
2704                    b = 10L * (b % s);
2705                    m *= 10L;
2706                    low  = (b <  m);
2707                    high = (b + m > tens);
2708                    if (q >= 10) {
2709                        // bummer, dude
2710                        throw new RuntimeException("Assertion botch: excessivly large digit " + q);
2711                    } else if ((q == 0) && ! high) {
2712                        // oops. Usually ignore leading zero.
2713                        decExp--;
2714                    } else {
2715                        digits[ndigit++] = (char)('0' + q);
2716                    }
2717                    /*
2718                     * HACK! Java spec sez that we always have at least
2719                     * one digit after the . in either F- or E-form output.
2720                     * Thus we will need more than one digit if we're using
2721                     * E-form
2722                     */
2723                    if (decExp <= -3 || decExp >= 8) {
2724                        high = low = false;
2725                    }
2726                    while (! low && ! high) {
2727                        q = (int) (b / s);
2728                        b = 10 * (b % s);
2729                        m *= 10;
2730                        if (q >= 10) {
2731                            // bummer, dude
2732                            throw new RuntimeException("Assertion botch: excessivly large digit " + q);
2733                        }
2734                        if (m > 0L) {
2735                            low  = (b <  m);
2736                            high = (b + m > tens);
2737                        } else {
2738                            // hack -- m might overflow!
2739                            // in this case, it is certainly > b,
2740                            // which won't
2741                            // and b+m > tens, too, since that has overflowed
2742                            // either!
2743                            low = true;
2744                            high = true;
2745                        }
2746                        digits[ndigit++] = (char)('0' + q);
2747                    }
2748                    lowDigitDifference = (b<<1) - tens;
2749                }
2750            } else {
2751                FDBigInt tenSval;
2752                int  shiftBias;
2753    
2754                /*
2755                 * We really must do FDBigInt arithmetic.
2756                 * Fist, construct our FDBigInt initial values.
2757                 */
2758                Bval = new FDBigInt(fractBits);
2759                if (B5 != 0) {
2760                    if (B5 < small5pow.length) {
2761                        Bval = Bval.mult(small5pow[B5]);
2762                    } else {
2763                        Bval = Bval.mult(big5pow(B5));
2764                    }
2765                }
2766                if (B2 != 0) {
2767                    Bval.lshiftMe(B2);
2768                }
2769                Sval = new FDBigInt(big5pow(S5));
2770                if (S2 != 0) {
2771                    Sval.lshiftMe(S2);
2772                }
2773                Mval = new FDBigInt(big5pow(M5));
2774                if (M2 != 0) {
2775                    Mval.lshiftMe(M2);
2776                }
2777    
2778    
2779                // normalize so that division works better
2780                Bval.lshiftMe(shiftBias = Sval.normalizeMe());
2781                Mval.lshiftMe(shiftBias);
2782                tenSval = Sval.mult(10);
2783                /*
2784                 * Unroll the first iteration. If our decExp estimate
2785                 * was too high, our first quotient will be zero. In this
2786                 * case, we discard it and decrement decExp.
2787                 */
2788                ndigit = 0;
2789                q = Bval.quoRemIteration(Sval);
2790                Mval = Mval.mult(10);
2791                low  = (Bval.cmp(Mval) < 0);
2792                high = (Bval.add(Mval).cmp(tenSval) > 0);
2793                if (q >= 10) {
2794                    // bummer, dude
2795                    throw new RuntimeException("Assertion botch: excessivly large digit " + q);
2796                } else if ((q == 0) && ! high) {
2797                    // oops. Usually ignore leading zero.
2798                    decExp--;
2799                } else {
2800                    digits[ndigit++] = (char)('0' + q);
2801                }
2802                /*
2803                 * HACK! Java spec sez that we always have at least
2804                 * one digit after the . in either F- or E-form output.
2805                 * Thus we will need more than one digit if we're using
2806                 * E-form
2807                 */
2808                if (decExp <= -3 || decExp >= 8) {
2809                    high = low = false;
2810                }
2811                while (! low && ! high) {
2812                    q = Bval.quoRemIteration(Sval);
2813                    Mval = Mval.mult(10);
2814                    if (q >= 10) {
2815                        // bummer, dude
2816                        throw new RuntimeException("Assertion botch: excessivly large digit " + q);
2817                    }
2818                    low  = (Bval.cmp(Mval) < 0);
2819                    high = (Bval.add(Mval).cmp(tenSval) > 0);
2820                    digits[ndigit++] = (char)('0' + q);
2821                }
2822                if (high && low) {
2823                    Bval.lshiftMe(1);
2824                    lowDigitDifference = Bval.cmp(tenSval);
2825                } else {
2826                    lowDigitDifference = 0L; // this here only for flow analysis!
2827                }
2828            }
2829            this.decExponent = decExp + 1;
2830            this.digits = digits;
2831            this.nDigits = ndigit;
2832            /*
2833             * Last digit gets rounded based on stopping condition.
2834             */
2835            if (high) {
2836                if (low) {
2837                    if (lowDigitDifference == 0L) {
2838                        // it's a tie!
2839                        // choose based on which digits we like.
2840                        if ((digits[nDigits - 1] & 1) != 0) {
2841                            roundup();
2842                        }
2843                    } else if (lowDigitDifference > 0) {
2844                        roundup();
2845                    }
2846                } else {
2847                    roundup();
2848                }
2849            }
2850        }
2851    
2852        public String
2853        toString() {
2854            // most brain-dead version
2855            StringBuilder result = new StringBuilder(nDigits + 8);
2856            if (isNegative) {
2857                result.append('-');
2858            }
2859            if (isExceptional) {
2860                result.append(digits, 0, nDigits);
2861            } else {
2862                result.append("0.");
2863                result.append(digits, 0, nDigits);
2864                result.append('e');
2865                result.append(decExponent);
2866            }
2867            return new String(result);
2868        }
2869    
2870        public String
2871        toJavaFormatString() {
2872            char result[] = new char[nDigits + 10];
2873            int  i = 0;
2874            if (isNegative) {
2875                result[0] = '-';
2876                i = 1;
2877            }
2878            if (isExceptional) {
2879                System.arraycopy(digits, 0, result, i, nDigits);
2880                i += nDigits;
2881            } else {
2882                if (decExponent > 0 && decExponent < 8) {
2883                    // print digits.digits.
2884                    int charLength = Math.min(nDigits, decExponent);
2885                    System.arraycopy(digits, 0, result, i, charLength);
2886                    i += charLength;
2887                    if (charLength < decExponent) {
2888                        charLength = decExponent - charLength;
2889                        System.arraycopy(zero, 0, result, i, charLength);
2890                        i += charLength;
2891                        result[i++] = '.';
2892                        result[i++] = '0';
2893                    } else {
2894                        result[i++] = '.';
2895                        if (charLength < nDigits) {
2896                            int t = nDigits - charLength;
2897                            System.arraycopy(digits, charLength, result, i, t);
2898                            i += t;
2899                        } else {
2900                            result[i++] = '0';
2901                        }
2902                    }
2903                } else if (decExponent <=0 && decExponent > -3) {
2904                    result[i++] = '0';
2905                    result[i++] = '.';
2906                    if (decExponent != 0) {
2907                        System.arraycopy(zero, 0, result, i, -decExponent);
2908                        i -= decExponent;
2909                    }
2910                    System.arraycopy(digits, 0, result, i, nDigits);
2911                    i += nDigits;
2912                } else {
2913                    result[i++] = digits[0];
2914                    result[i++] = '.';
2915                    if (nDigits > 1) {
2916                        System.arraycopy(digits, 1, result, i, nDigits - 1);
2917                        i += nDigits - 1;
2918                    } else {
2919                        result[i++] = '0';
2920                    }
2921                    result[i++] = 'E';
2922                    int e;
2923                    if (decExponent <= 0) {
2924                        result[i++] = '-';
2925                        e = -decExponent + 1;
2926                    } else {
2927                        e = decExponent - 1;
2928                    }
2929                    // decExponent has 1, 2, or 3, digits
2930                    if (e <= 9) {
2931                        result[i++] = (char)(e + '0');
2932                    } else if (e <= 99) {
2933                        result[i++] = (char)(e / 10 + '0');
2934                        result[i++] = (char)(e % 10 + '0');
2935                    } else {
2936                        result[i++] = (char)(e / 100 + '0');
2937                        e %= 100;
2938                        result[i++] = (char)(e / 10 + '0');
2939                        result[i++] = (char)(e % 10 + '0');
2940                    }
2941                }
2942            }
2943            return new String(result, 0, i);
2944        }
2945    
2946        // jhyde added
2947        public FloatingDecimal(long n)
2948        {
2949            isExceptional = false; // I don't think longs can be exceptional
2950            if (n < 0) {
2951                isNegative = true;
2952                n = -n; // if n == MIN_LONG, oops!
2953            } else {
2954                isNegative = false;
2955            }
2956            if (n == 0) {
2957                nDigits = 1;
2958                digits = new char[] {'0','0','0','0','0','0','0','0'};
2959                decExponent = 0;
2960            } else {
2961                nDigits = 0;
2962                for (long m = n; m != 0; m = m / 10) {
2963                    nDigits++;
2964                }
2965                decExponent = nDigits;
2966                digits = new char[nDigits];
2967                int i = nDigits - 1;
2968                for (long m = n; m != 0; m = m / 10) {
2969                    digits[i--] = (char) ('0' + (m % 10));
2970                }
2971            }
2972        }
2973    
2974        // jhyde added
2975        public void shift(int i)
2976        {
2977            if (isExceptional ||
2978                nDigits == 1 && digits[0] == '0') {
2979                ; // don't multiply zero
2980            } else {
2981                decExponent += i;
2982            }
2983        }
2984    
2985        // jhyde added
2986        public String toJavaFormatString(
2987            int minDigitsLeftOfDecimal,
2988            char decimalChar, // '.' or ','
2989            int minDigitsRightOfDecimal,
2990            int maxDigitsRightOfDecimal, // todo: use
2991            char expChar, // 'E' or 'e'
2992            boolean expSign, // whether to print '+' if exp is positive
2993            int minExpDigits, // minimum digits in exponent
2994            char thousandChar) // ',' or '.', or 0
2995        {
2996            // char result[] = new char[nDigits + 10]; // crashes for 1.000.000,00
2997            // the result length does *not* depend from nDigits
2998            //  it is : decExponent
2999            //         +maxDigitsRightOfDecimal
3000            //          + 10  (for decimal point and sign or -Infinity)
3001            //         +decExponent/3 (for the thousand separators)
3002            int resultLen = 10 + Math.abs(decExponent) * 4 / 3 + maxDigitsRightOfDecimal;
3003            char result[] = new char[resultLen];
3004            int i = toJavaFormatString(
3005                result, 0, minDigitsLeftOfDecimal, decimalChar,
3006                minDigitsRightOfDecimal, maxDigitsRightOfDecimal, expChar, expSign,
3007                minExpDigits, thousandChar);
3008            return new String(result, 0, i);
3009        }
3010    
3011        // jhyde added
3012        private synchronized int toJavaFormatString(
3013            char result[],
3014            int i,
3015            int minDigitsLeftOfDecimal,
3016            char decimalChar, // '.' or ','
3017            int minDigitsRightOfDecimal,
3018            int maxDigitsRightOfDecimal, // todo: use
3019            char expChar, // 'E' or 'e'
3020            boolean expSign, // whether to print '+' if exp is positive
3021            int minExpDigits, // minimum digits in exponent
3022            char thousandChar) // ',' or '.' or 0
3023        {
3024            if (isNegative) {
3025                result[i++] = '-';
3026            }
3027            if (isExceptional) {
3028                System.arraycopy(digits, 0, result, i, nDigits);
3029                i += nDigits;
3030            } else if (expChar == 0) {
3031                // Build a new array of digits, padded with 0s at either end.  For
3032                // example, here is the array we would build for 1234.56.
3033                //
3034                // |  0     0     1     2     3  .  4     5     6     0     0   |
3035                // |           |- nDigits=6 -----------------------|            |
3036                // |           |- decExponent=3 -|                              |
3037                // |- minDigitsLeftOfDecimal=5 --|                              |
3038                // |                             |- minDigitsRightOfDecimal=5 --|
3039                // |- wholeDigits=5 -------------|- fractionDigits=5 -----------|
3040                // |- totalDigits=10 -------------------------------------------|
3041                // |                             |- maxDigitsRightOfDecimal=5 --|
3042                int wholeDigits = Math.max(decExponent, minDigitsLeftOfDecimal),
3043                    fractionDigits = Math.max(
3044                        nDigits - decExponent, minDigitsRightOfDecimal),
3045                    totalDigits = wholeDigits + fractionDigits;
3046                char[] digits2 = new char[totalDigits];
3047                for (int j = 0; j < totalDigits; j++) {
3048                    digits2[j] = '0';
3049                }
3050                for (int j = 0; j < nDigits; j++) {
3051                    digits2[wholeDigits - decExponent + j] = digits[j];
3052                }
3053    
3054                // Now round.  Suppose that we want to round 1234.56 to 1 decimal
3055                // place (that is, maxDigitsRightOfDecimal = 1).  Then lastDigit
3056                // initially points to '5'.  We find out that we need to round only
3057                // when we see that the next digit ('6') is non-zero.
3058                //
3059                // |  0     0     1     2     3  .  4     5     6     0     0   |
3060                // |                             |  ^   |                       |
3061                // |                                maxDigitsRightOfDecimal=1   |
3062                int lastDigit = wholeDigits + maxDigitsRightOfDecimal;
3063                if (lastDigit < totalDigits) {
3064                    // We need to truncate -- also round if the trailing digits are
3065                    // 5000... or greater.
3066                    int m = totalDigits;
3067                    while (true) {
3068                        m--;
3069                        if (m < 0) {
3070                            // The entire number was 9s.  Re-allocate, so we can
3071                            // prepend a '1'.
3072                            wholeDigits++;
3073                            totalDigits++;
3074                            lastDigit++;
3075                            char[] old = digits2;
3076                            digits2 = new char[totalDigits];
3077                            digits2[0] = '1';
3078                            System.arraycopy(old, 0, digits2, 1, old.length);
3079                            break;
3080                        } else if (m == lastDigit) {
3081                            char d = digits2[m];
3082                            digits2[m] = '0';
3083                            if (d < '5') {
3084                                break; // no need to round
3085                            }
3086                        } else if (m > lastDigit) {
3087                            digits2[m] = '0';
3088                        } else if (digits2[m] == '9') {
3089                            digits2[m] = '0';
3090                            // do not break - we have to carry
3091                        } else {
3092                            digits2[m]++;
3093                            break; // nothing to carry
3094                        }
3095                    }
3096                }
3097    
3098                // Find the first non-zero digit and the last non-zero digit.
3099                int firstNonZero = wholeDigits,
3100                    firstTrailingZero = 0;
3101                for (int j = 0; j < totalDigits; j++) {
3102                    if (digits2[j] != '0') {
3103                        if (j < firstNonZero) {
3104                            firstNonZero = j;
3105                        }
3106                        firstTrailingZero = j + 1;
3107                    }
3108                }
3109    
3110                int firstDigitToPrint = firstNonZero;
3111                if (firstDigitToPrint > wholeDigits - minDigitsLeftOfDecimal) {
3112                    firstDigitToPrint = wholeDigits - minDigitsLeftOfDecimal;
3113                }
3114                int lastDigitToPrint = firstTrailingZero;
3115                if (lastDigitToPrint > wholeDigits + maxDigitsRightOfDecimal) {
3116                    lastDigitToPrint = wholeDigits + maxDigitsRightOfDecimal;
3117                }
3118                if (lastDigitToPrint < wholeDigits + minDigitsRightOfDecimal) {
3119                    lastDigitToPrint = wholeDigits + minDigitsRightOfDecimal;
3120                }
3121    
3122                // Now print the number.
3123                for (int j = firstDigitToPrint; j < wholeDigits; j++) {
3124                    if (thousandChar != '\0' &&
3125                        (wholeDigits - j) % 3 == 0 &&
3126                        j > firstDigitToPrint &&
3127                        j < wholeDigits - 1) {
3128                        result[i++] = thousandChar;
3129                    }
3130                    result[i++] = digits2[j];
3131                }
3132                for (int j = wholeDigits; j < lastDigitToPrint; j++) {
3133                    if (j == wholeDigits) {
3134                        result[i++] = decimalChar;
3135                    }
3136                    result[i++] = digits2[j];
3137                }
3138            } else {
3139                // Make a recursive call to print the digits left of the 'E'.
3140                int oldExp = decExponent;
3141                decExponent = Math.min(minDigitsLeftOfDecimal, nDigits);
3142                boolean oldIsNegative = isNegative;
3143                isNegative = false;
3144                i = toJavaFormatString(
3145                    result, i, minDigitsLeftOfDecimal, decimalChar,
3146                    minDigitsRightOfDecimal, maxDigitsRightOfDecimal, (char) 0,
3147                    false, minExpDigits, '\0');
3148                decExponent = oldExp;
3149                isNegative = oldIsNegative;
3150    
3151                result[i++] = expChar;
3152                int de = decExponent;
3153                if (nDigits == 1 && digits[0] == '0') {
3154                    de = 1; // 0's exponent is 0, but that's not convenient here
3155                }
3156                int e;
3157                if (de <= 0) {
3158                    result[i++] = '-';
3159                    e = -de + 1;
3160                } else {
3161                    if (expSign) {
3162                        result[i++] = '+';
3163                    }
3164                    e = de - 1;
3165                }
3166                // decExponent has 1, 2, or 3, digits
3167                int nExpDigits = e <= 9 ? 1 : e <= 99 ? 2 : 3;
3168                for (int j = nExpDigits; j < minExpDigits; j++) {
3169                    result[i++] = '0';
3170                }
3171                if (e <= 9) {
3172                    result[i++] = (char)(e + '0');
3173                } else if (e <= 99) {
3174                    result[i++] = (char)(e / 10 + '0');
3175                    result[i++] = (char)(e % 10 + '0');
3176                } else {
3177                    result[i++] = (char)(e / 100 + '0');
3178                    e %= 100;
3179                    result[i++] = (char)(e / 10 + '0');
3180                    result[i++] = (char)(e % 10 + '0');
3181                }
3182            }
3183            return i;
3184        }
3185    
3186        private static final int small5pow[] = {
3187            1,
3188            5,
3189            5 * 5,
3190            5 * 5 * 5,
3191            5 * 5 * 5 * 5,
3192            5 * 5 * 5 * 5 * 5,
3193            5 * 5 * 5 * 5 * 5 * 5,
3194            5 * 5 * 5 * 5 * 5 * 5 * 5,
3195            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3196            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3197            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3198            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3199            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3200            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
3201        };
3202    
3203        private static final long long5pow[] = {
3204            1L,
3205            5L,
3206            5L * 5,
3207            5L * 5 * 5,
3208            5L * 5 * 5 * 5,
3209            5L * 5 * 5 * 5 * 5,
3210            5L * 5 * 5 * 5 * 5 * 5,
3211            5L * 5 * 5 * 5 * 5 * 5 * 5,
3212            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3213            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3214            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3215            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3216            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3217            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3218            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3219            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3220            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3221            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3222            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3223            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3224            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3225            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3226            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3227            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3228            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3229            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3230            5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
3231        };
3232    
3233        // approximately ceil(log2(long5pow[i]))
3234        private static final int n5bits[] = {
3235            0,
3236            3,
3237            5,
3238            7,
3239            10,
3240            12,
3241            14,
3242            17,
3243            19,
3244            21,
3245            24,
3246            26,
3247            28,
3248            31,
3249            33,
3250            35,
3251            38,
3252            40,
3253            42,
3254            45,
3255            47,
3256            49,
3257            52,
3258            54,
3259            56,
3260            59,
3261            61,
3262        };
3263    
3264        private static final char infinity[] = { 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y' };
3265        private static final char notANumber[] = { 'N', 'a', 'N' };
3266        private static final char zero[] = { '0', '0', '0', '0', '0', '0', '0', '0' };
3267    }
3268    
3269    /*
3270     * A really, really simple bigint package
3271     * tailored to the needs of floating base conversion.
3272     */
3273    static class FDBigInt {
3274        int nWords; // number of words used
3275        int data[]; // value: data[0] is least significant
3276    
3277        private static boolean debugging = false;
3278    
3279        public static void setDebugging(boolean d) {
3280            debugging = d;
3281        }
3282    
3283        public FDBigInt(int v) {
3284            nWords = 1;
3285            data = new int[1];
3286            data[0] = v;
3287        }
3288    
3289        public FDBigInt(long v) {
3290            data = new int[2];
3291            data[0] = (int)v;
3292            data[1] = (int)(v>>>32);
3293            nWords = (data[1] == 0) ? 1 : 2;
3294        }
3295    
3296        public FDBigInt(FDBigInt other) {
3297            data = new int[nWords = other.nWords];
3298            System.arraycopy(other.data, 0, data, 0, nWords);
3299        }
3300    
3301        private FDBigInt(int [] d, int n) {
3302            data = d;
3303            nWords = n;
3304        }
3305    
3306        /*
3307         * Left shift by c bits.
3308         * Shifts this in place.
3309         */
3310        public void
3311        lshiftMe(int c)throws IllegalArgumentException {
3312            if (c <= 0) {
3313                if (c == 0) {
3314                    return; // silly.
3315                } else {
3316                    throw new IllegalArgumentException("negative shift count");
3317                }
3318            }
3319            int wordcount = c>>5;
3320            int bitcount  = c & 0x1f;
3321            int anticount = 32 - bitcount;
3322            int t[] = data;
3323            int s[] = data;
3324            if (nWords + wordcount + 1 > t.length) {
3325                // reallocate.
3326                t = new int[nWords + wordcount + 1];
3327            }
3328            int target = nWords + wordcount;
3329            int src    = nWords - 1;
3330            if (bitcount == 0) {
3331                // special hack, since an anticount of 32 won't go!
3332                System.arraycopy(s, 0, t, wordcount, nWords);
3333                target = wordcount - 1;
3334            } else {
3335                t[target--] = s[src]>>>anticount;
3336                while (src >= 1) {
3337                    t[target--] = (s[src]<<bitcount) | (s[--src]>>>anticount);
3338                }
3339                t[target--] = s[src]<<bitcount;
3340            }
3341            while (target >= 0) {
3342                t[target--] = 0;
3343            }
3344            data = t;
3345            nWords += wordcount + 1;
3346            // may have constructed high-order word of 0.
3347            // if so, trim it
3348            while (nWords > 1 && data[nWords - 1] == 0) {
3349                nWords--;
3350            }
3351        }
3352    
3353        /*
3354         * normalize this number by shifting until
3355         * the MSB of the number is at 0x08000000.
3356         * This is in preparation for quoRemIteration, below.
3357         * The idea is that, to make division easier, we want the
3358         * divisor to be "normalized" -- usually this means shifting
3359         * the MSB into the high words sign bit. But because we know that
3360         * the quotient will be 0 < q < 10, we would like to arrange that
3361         * the dividend not span up into another word of precision.
3362         * (This needs to be explained more clearly!)
3363         */
3364        public int
3365        normalizeMe() throws IllegalArgumentException {
3366            int src;
3367            int wordcount = 0;
3368            int bitcount  = 0;
3369            int v = 0;
3370            for (src = nWords - 1 ; src >= 0 && (v = data[src]) == 0; src--) {
3371                wordcount += 1;
3372            }
3373            if (src < 0) {
3374                // oops. Value is zero. Cannot normalize it!
3375                throw new IllegalArgumentException("zero value");
3376            }
3377            /*
3378             * In most cases, we assume that wordcount is zero. This only
3379             * makes sense, as we try not to maintain any high-order
3380             * words full of zeros. In fact, if there are zeros, we will
3381             * simply SHORTEN our number at this point. Watch closely...
3382             */
3383            nWords -= wordcount;
3384            /*
3385             * Compute how far left we have to shift v s.t. its highest-
3386             * order bit is in the right place. Then call lshiftMe to
3387             * do the work.
3388             */
3389            if ((v & 0xf0000000) != 0) {
3390                // will have to shift up into the next word.
3391                // too bad.
3392                for (bitcount = 32 ; (v & 0xf0000000) != 0 ; bitcount--) {
3393                    v >>>= 1;
3394                }
3395            } else {
3396                while (v <= 0x000fffff) {
3397                    // hack: byte-at-a-time shifting
3398                    v <<= 8;
3399                    bitcount += 8;
3400                }
3401                while (v <= 0x07ffffff) {
3402                    v <<= 1;
3403                    bitcount += 1;
3404                }
3405            }
3406            if (bitcount != 0)
3407                lshiftMe(bitcount);
3408            return bitcount;
3409        }
3410    
3411        /*
3412         * Multiply a FDBigInt by an int.
3413         * Result is a new FDBigInt.
3414         */
3415        public FDBigInt
3416        mult(int iv) {
3417            long v = iv;
3418            int r[];
3419            long p;
3420    
3421            // guess adequate size of r.
3422            r = new int[(v * ((long)data[nWords - 1] & 0xffffffffL) > 0xfffffffL) ? nWords + 1 : nWords];
3423            p = 0L;
3424            for (int i = 0; i < nWords; i++) {
3425                p += v * ((long)data[i] & 0xffffffffL);
3426                r[i] = (int)p;
3427                p >>>= 32;
3428            }
3429            if (p == 0L) {
3430                return new FDBigInt(r, nWords);
3431            } else {
3432                r[nWords] = (int)p;
3433                return new FDBigInt(r, nWords + 1);
3434            }
3435        }
3436    
3437        /*
3438         * Multiply a FDBigInt by another FDBigInt.
3439         * Result is a new FDBigInt.
3440         */
3441        public FDBigInt
3442        mult(FDBigInt other) {
3443            // crudely guess adequate size for r
3444            int r[] = new int[nWords + other.nWords];
3445            int i;
3446            // I think I am promised zeros...
3447    
3448            for (i = 0; i < this.nWords; i++) {
3449                long v = (long)this.data[i] & 0xffffffffL; // UNSIGNED CONVERSION
3450                long p = 0L;
3451                int j;
3452                for (j = 0; j < other.nWords; j++) {
3453                    p += ((long)r[i + j] & 0xffffffffL) + v * ((long)other.data[j] & 0xffffffffL); // UNSIGNED CONVERSIONS ALL 'ROUND.
3454                    r[i + j] = (int)p;
3455                    p >>>= 32;
3456                }
3457                r[i + j] = (int)p;
3458            }
3459            // compute how much of r we actually needed for all that.
3460            for (i = r.length - 1; i > 0; i--) {
3461                if (r[i] != 0) {
3462                    break;
3463                }
3464            }
3465            return new FDBigInt(r, i + 1);
3466        }
3467    
3468        /*
3469         * Add one FDBigInt to another. Return a FDBigInt
3470         */
3471        public FDBigInt
3472        add(FDBigInt other) {
3473            int i;
3474            int a[], b[];
3475            int n, m;
3476            long c = 0L;
3477            // arrange such that a.nWords >= b.nWords;
3478            // n = a.nWords, m = b.nWords
3479            if (this.nWords >= other.nWords) {
3480                a = this.data;
3481                n = this.nWords;
3482                b = other.data;
3483                m = other.nWords;
3484            } else {
3485                a = other.data;
3486                n = other.nWords;
3487                b = this.data;
3488                m = this.nWords;
3489            }
3490            int r[] = new int[n];
3491            for (i = 0; i < n; i++) {
3492                c += (long)a[i] & 0xffffffffL;
3493                if (i < m) {
3494                    c += (long)b[i] & 0xffffffffL;
3495                }
3496                r[i] = (int) c;
3497                c >>= 32; // signed shift.
3498            }
3499            if (c != 0L) {
3500                // oops -- carry out -- need longer result.
3501                int s[] = new int[r.length + 1];
3502                System.arraycopy(r, 0, s, 0, r.length);
3503                s[i++] = (int)c;
3504                return new FDBigInt(s, i);
3505            }
3506            return new FDBigInt(r, i);
3507        }
3508    
3509        /*
3510         * Subtract one FDBigInt from another. Return a FDBigInt
3511         * Assert that the result is positive.
3512         */
3513        public FDBigInt
3514        sub(FDBigInt other) {
3515            int r[] = new int[this.nWords];
3516            int i;
3517            int n = this.nWords;
3518            int m = other.nWords;
3519            int nzeros = 0;
3520            long c = 0L;
3521            for (i = 0; i < n; i++) {
3522                c += (long)this.data[i] & 0xffffffffL;
3523                if (i < m) {
3524                    c -= (long)other.data[i] & 0xffffffffL;
3525                }
3526                if ((r[i] = (int) c) == 0) {
3527                    nzeros++;
3528                } else {
3529                    nzeros = 0;
3530                }
3531                c >>= 32; // signed shift.
3532            }
3533            if (c != 0L)
3534                throw new RuntimeException("Assertion botch: borrow out of subtract");
3535            while (i < m)
3536                if (other.data[i++] != 0)
3537                    throw new RuntimeException("Assertion botch: negative result of subtract");
3538            return new FDBigInt(r, n - nzeros);
3539        }
3540    
3541        /*
3542         * Compare FDBigInt with another FDBigInt. Return an integer
3543         * >0: this > other
3544         *  0: this == other
3545         * <0: this < other
3546         */
3547        public int
3548        cmp(FDBigInt other) {
3549            int i;
3550            if (this.nWords > other.nWords) {
3551                // if any of my high-order words is non-zero,
3552                // then the answer is evident
3553                int j = other.nWords - 1;
3554                for (i = this.nWords - 1; i > j ; i--) {
3555                    if (this.data[i] != 0) {
3556                        return 1;
3557                    }
3558                }
3559            } else if (this.nWords < other.nWords) {
3560                // if any of other's high-order words is non-zero,
3561                // then the answer is evident
3562                int j = this.nWords - 1;
3563                for (i = other.nWords - 1; i > j ; i--) {
3564                    if (other.data[i] != 0) {
3565                        return -1;
3566                    }
3567                }
3568            } else {
3569                i = this.nWords - 1;
3570            }
3571            for (; i > 0 ; i--)
3572                if (this.data[i] != other.data[i])
3573                    break;
3574            // careful! want unsigned compare!
3575            // use brute force here.
3576            int a = this.data[i];
3577            int b = other.data[i];
3578            if (a < 0) {
3579                // a is really big, unsigned
3580                if (b < 0) {
3581                    return a - b; // both big, negative
3582                } else {
3583                    return 1; // b not big, answer is obvious;
3584                }
3585            } else {
3586                // a is not really big
3587                if (b < 0) {
3588                    // but b is really big
3589                    return -1;
3590                } else {
3591                    return a - b;
3592                }
3593            }
3594        }
3595    
3596        /*
3597         * Compute
3598         * q = (int)(this / S)
3599         * this = 10 * (this mod S)
3600         * Return q.
3601         * This is the iteration step of digit development for output.
3602         * We assume that S has been normalized, as above, and that
3603         * "this" has been lshift'ed accordingly.
3604         * Also assume, of course, that the result, q, can be expressed
3605         * as an integer, 0 <= q < 10.
3606         */
3607        public int
3608        quoRemIteration(FDBigInt S)throws IllegalArgumentException {
3609            // ensure that this and S have the same number of
3610            // digits. If S is properly normalized and q < 10 then
3611            // this must be so.
3612            if (nWords != S.nWords) {
3613                throw new IllegalArgumentException("disparate values");
3614            }
3615            // estimate q the obvious way. We will usually be
3616            // right. If not, then we're only off by a little and
3617            // will re-add.
3618            int n = nWords - 1;
3619            long q = ((long)data[n] & 0xffffffffL) / (long)S.data[n];
3620            long diff = 0L;
3621            for (int i = 0; i <= n ; i++) {
3622                diff += ((long)data[i] & 0xffffffffL) -  q * ((long)S.data[i] & 0xffffffffL);
3623                data[i] = (int)diff;
3624                diff >>= 32; // N.B. SIGNED shift.
3625            }
3626            if (diff != 0L) {
3627                // damn, damn, damn. q is too big.
3628                // add S back in until this turns +. This should
3629                // not be very many times!
3630                long sum = 0L;
3631                while (sum ==  0L) {
3632                    sum = 0L;
3633                    for (int i = 0; i <= n; i++) {
3634                        sum += ((long)data[i] & 0xffffffffL) +  ((long)S.data[i] & 0xffffffffL);
3635                        data[i] = (int) sum;
3636                        sum >>= 32; // Signed or unsigned, answer is 0 or 1
3637                    }
3638                    /*
3639                     * Originally the following line read
3640                     * "if (sum !=0 && sum != -1)"
3641                     * but that would be wrong, because of the
3642                     * treatment of the two values as entirely unsigned,
3643                     * it would be impossible for a carry-out to be interpreted
3644                     * as -1 -- it would have to be a single-bit carry-out, or
3645                     *  + 1.
3646                     */
3647                    if (sum != 0 && sum != 1) {
3648                        throw new RuntimeException("Assertion botch: " + sum + " carry out of division correction");
3649                    }
3650                    q -= 1;
3651                }
3652            }
3653            // finally, we can multiply this by 10.
3654            // it cannot overflow, right, as the high-order word has
3655            // at least 4 high-order zeros!
3656            long p = 0L;
3657            for (int i = 0; i <= n; i++) {
3658                p += 10 * ((long)data[i] & 0xffffffffL);
3659                data[i] = (int)p;
3660                p >>= 32; // SIGNED shift.
3661            }
3662            if (p != 0L)
3663                throw new RuntimeException("Assertion botch: carry out of *10");
3664    
3665            return (int)q;
3666        }
3667    
3668        public long
3669        longValue() {
3670            // if this can be represented as a long,
3671            // return the value
3672            int i;
3673            for (i = this.nWords - 1; i > 1 ; i--) {
3674                if (data[i] != 0) {
3675                    throw new RuntimeException("Assertion botch: value too big");
3676                }
3677            }
3678            switch (i) {
3679            case 1:
3680                if (data[1] < 0)
3681                    throw new RuntimeException("Assertion botch: value too big");
3682                return ((long)(data[1]) << 32) | ((long)data[0] & 0xffffffffL);
3683            case 0:
3684                return ((long)data[0] & 0xffffffffL);
3685            default:
3686                throw new RuntimeException("Assertion botch: longValue confused");
3687            }
3688        }
3689    
3690        public String
3691        toString() {
3692            StringBuilder r = new StringBuilder(30);
3693            r.append('[');
3694            int i = Math.min(nWords - 1, data.length - 1);
3695            if (nWords > data.length) {
3696                r.append("(" + data.length + "<" + nWords + "!)");
3697            }
3698            for (; i > 0 ; i--) {
3699                r.append(Integer.toHexString(data[i]));
3700                r.append(' ');
3701            }
3702            r.append(Integer.toHexString(data[0]));
3703            r.append(']');
3704            return new String(r);
3705        }
3706    }
3707    }
3708    
3709    // End Format.java