Initial revision
From-SVN: r26263
This commit is contained in:
parent
140fa895c6
commit
ee9dd3721b
370 changed files with 173494 additions and 0 deletions
160
libjava/java/text/BreakIterator.java
Normal file
160
libjava/java/text/BreakIterator.java
Normal file
|
@ -0,0 +1,160 @@
|
|||
// BreakIterator.java - Iterate over logical breaks in text.
|
||||
|
||||
/* Copyright (C) 1999 Cygnus Solutions
|
||||
|
||||
This file is part of libgcj.
|
||||
|
||||
This software is copyrighted work licensed under the terms of the
|
||||
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
||||
details. */
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Locale;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* @author Tom Tromey <tromey@cygnus.com>
|
||||
* @date March 19, 1999
|
||||
*/
|
||||
/* Written using "Java Class Libraries", 2nd edition, plus online
|
||||
* API docs for JDK 1.2 beta from http://www.javasoft.com.
|
||||
* Status: Believed complete and correct to 1.1.
|
||||
*/
|
||||
|
||||
public abstract class BreakIterator implements Cloneable, Serializable
|
||||
{
|
||||
// The value was discovered by writing a test program.
|
||||
public static final int DONE = -1;
|
||||
|
||||
protected BreakIterator ()
|
||||
{
|
||||
}
|
||||
|
||||
public abstract int current ();
|
||||
public abstract int first ();
|
||||
public abstract int following (int pos);
|
||||
|
||||
public static synchronized Locale[] getAvailableLocales ()
|
||||
{
|
||||
// FIXME.
|
||||
return null;
|
||||
}
|
||||
|
||||
private static BreakIterator getInstance (String type, Locale loc)
|
||||
{
|
||||
String className;
|
||||
try
|
||||
{
|
||||
ResourceBundle res
|
||||
= ResourceBundle.getBundle("gnu.gcj.text.LocaleData", loc);
|
||||
className = res.getString(type);
|
||||
}
|
||||
catch (MissingResourceException x)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
Class k = Class.forName(className);
|
||||
return (BreakIterator) k.newInstance();
|
||||
}
|
||||
catch (ClassNotFoundException x1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
catch (InstantiationException x2)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
catch (IllegalAccessException x3)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static BreakIterator getCharacterInstance ()
|
||||
{
|
||||
return getCharacterInstance (Locale.getDefault());
|
||||
}
|
||||
|
||||
public static BreakIterator getCharacterInstance (Locale loc)
|
||||
{
|
||||
BreakIterator r = getInstance ("CharacterIterator", loc);
|
||||
if (r == null)
|
||||
r = new gnu.gcj.text.CharacterBreakIterator ();
|
||||
return r;
|
||||
}
|
||||
|
||||
public static BreakIterator getLineInstance ()
|
||||
{
|
||||
return getLineInstance (Locale.getDefault());
|
||||
}
|
||||
|
||||
public static BreakIterator getLineInstance (Locale loc)
|
||||
{
|
||||
BreakIterator r = getInstance ("LineIterator", loc);
|
||||
if (r == null)
|
||||
r = new gnu.gcj.text.LineBreakIterator ();
|
||||
return r;
|
||||
}
|
||||
|
||||
public static BreakIterator getSentenceInstance ()
|
||||
{
|
||||
return getSentenceInstance (Locale.getDefault());
|
||||
}
|
||||
|
||||
public static BreakIterator getSentenceInstance (Locale loc)
|
||||
{
|
||||
BreakIterator r = getInstance ("SentenceIterator", loc);
|
||||
if (r == null)
|
||||
r = new gnu.gcj.text.SentenceBreakIterator ();
|
||||
return r;
|
||||
}
|
||||
|
||||
public abstract CharacterIterator getText ();
|
||||
|
||||
public static BreakIterator getWordInstance ()
|
||||
{
|
||||
return getWordInstance (Locale.getDefault());
|
||||
}
|
||||
|
||||
public static BreakIterator getWordInstance (Locale loc)
|
||||
{
|
||||
BreakIterator r = getInstance ("WordIterator", loc);
|
||||
if (r == null)
|
||||
r = new gnu.gcj.text.WordBreakIterator ();
|
||||
return r;
|
||||
}
|
||||
|
||||
public boolean isBoundary (int pos)
|
||||
{
|
||||
if (pos == 0)
|
||||
return true;
|
||||
return following (pos - 1) == pos;
|
||||
}
|
||||
|
||||
public abstract int last ();
|
||||
public abstract int next ();
|
||||
public abstract int next (int n);
|
||||
|
||||
public int preceding (int pos)
|
||||
{
|
||||
if (following (pos) == DONE)
|
||||
last ();
|
||||
while (previous () >= pos)
|
||||
;
|
||||
return current ();
|
||||
}
|
||||
|
||||
public abstract int previous ();
|
||||
|
||||
public void setText (String newText)
|
||||
{
|
||||
setText (new StringCharacterIterator (newText));
|
||||
}
|
||||
|
||||
public abstract void setText (CharacterIterator newText);
|
||||
}
|
36
libjava/java/text/CharacterIterator.java
Normal file
36
libjava/java/text/CharacterIterator.java
Normal file
|
@ -0,0 +1,36 @@
|
|||
// CharacterIterator.java - Protocol for iterating over Unicode characters.
|
||||
|
||||
/* Copyright (C) 1999 Cygnus Solutions
|
||||
|
||||
This file is part of libgcj.
|
||||
|
||||
This software is copyrighted work licensed under the terms of the
|
||||
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
||||
details. */
|
||||
|
||||
package java.text;
|
||||
|
||||
/**
|
||||
* @author Tom Tromey <tromey@cygnus.com>
|
||||
* @date February 22, 1999
|
||||
*/
|
||||
/* Written using "Java Class Libraries", 2nd edition, plus online
|
||||
* API docs for JDK 1.2 beta from http://www.javasoft.com.
|
||||
* Status: Believed complete and correct to 1.1.
|
||||
*/
|
||||
|
||||
public interface CharacterIterator extends Cloneable
|
||||
{
|
||||
public abstract Object clone ();
|
||||
public abstract char current ();
|
||||
public abstract char first ();
|
||||
public abstract int getBeginIndex ();
|
||||
public abstract int getEndIndex ();
|
||||
public abstract int getIndex ();
|
||||
public abstract char last ();
|
||||
public abstract char next ();
|
||||
public abstract char previous ();
|
||||
public abstract char setIndex (int idx);
|
||||
|
||||
public static final char DONE = '\uffff';
|
||||
}
|
310
libjava/java/text/ChoiceFormat.java
Normal file
310
libjava/java/text/ChoiceFormat.java
Normal file
|
@ -0,0 +1,310 @@
|
|||
// ChoiceFormat.java - Formatter for `switch'-like string substitution.
|
||||
|
||||
/* Copyright (C) 1999 Cygnus Solutions
|
||||
|
||||
This file is part of libgcj.
|
||||
|
||||
This software is copyrighted work licensed under the terms of the
|
||||
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
||||
details. */
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* @author Tom Tromey <tromey@cygnus.com>
|
||||
* @date March 9, 1999
|
||||
*/
|
||||
/* Written using "Java Class Libraries", 2nd edition, plus online
|
||||
* API docs for JDK 1.2 from http://www.javasoft.com.
|
||||
* Status: Believed complete and correct to 1.1.
|
||||
*/
|
||||
|
||||
public class ChoiceFormat extends NumberFormat
|
||||
{
|
||||
// Note: we assume the same kind of quoting rules apply here.
|
||||
// This isn't explicitly documented. But for instance we accept
|
||||
// '#' as a literal hash in a format string.
|
||||
public void applyPattern (String newPattern)
|
||||
{
|
||||
int index = 0, max = newPattern.length();
|
||||
Vector stringVec = new Vector ();
|
||||
Vector limitVec = new Vector ();
|
||||
StringBuffer buf = new StringBuffer ();
|
||||
|
||||
while (true)
|
||||
{
|
||||
// Find end of double.
|
||||
int dstart = index;
|
||||
while (index < max)
|
||||
{
|
||||
char c = newPattern.charAt(index);
|
||||
if (c == '#' || c == '\u2064' || c == '<')
|
||||
break;
|
||||
++index;
|
||||
}
|
||||
|
||||
if (index == max)
|
||||
throw new IllegalArgumentException ("unexpected end of text");
|
||||
Double d = new Double (newPattern.substring(dstart, index));
|
||||
|
||||
if (newPattern.charAt(index) == '<')
|
||||
d = new Double (nextDouble (d.doubleValue()));
|
||||
|
||||
limitVec.addElement(d);
|
||||
|
||||
// Scan text.
|
||||
++index;
|
||||
buf.setLength(0);
|
||||
while (index < max)
|
||||
{
|
||||
char c = newPattern.charAt(index);
|
||||
if (c == '\'' && index < max + 1
|
||||
&& newPattern.charAt(index + 1) == '\'')
|
||||
{
|
||||
buf.append(c);
|
||||
++index;
|
||||
}
|
||||
else if (c == '\'' && index < max + 2)
|
||||
{
|
||||
buf.append(newPattern.charAt(index + 1));
|
||||
index += 2;
|
||||
}
|
||||
else if (c == '|')
|
||||
break;
|
||||
else
|
||||
buf.append(c);
|
||||
++index;
|
||||
}
|
||||
|
||||
stringVec.addElement(buf.toString());
|
||||
if (index == max)
|
||||
break;
|
||||
++index;
|
||||
}
|
||||
|
||||
strings = new String[stringVec.size()];
|
||||
stringVec.copyInto(strings);
|
||||
|
||||
limits = new double[limitVec.size()];
|
||||
for (int i = 0; i < limits.length; ++i)
|
||||
{
|
||||
Double d = (Double) limitVec.elementAt(i);
|
||||
limits[i] = d.doubleValue();
|
||||
}
|
||||
}
|
||||
|
||||
public ChoiceFormat (String newPattern)
|
||||
{
|
||||
super ();
|
||||
applyPattern (newPattern);
|
||||
}
|
||||
|
||||
public ChoiceFormat (double[] limits, String[] strings)
|
||||
{
|
||||
super ();
|
||||
setChoices (limits, strings);
|
||||
}
|
||||
|
||||
public Object clone ()
|
||||
{
|
||||
return new ChoiceFormat (limits, strings);
|
||||
}
|
||||
|
||||
public boolean equals (Object obj)
|
||||
{
|
||||
if (! (obj instanceof ChoiceFormat))
|
||||
return false;
|
||||
ChoiceFormat cf = (ChoiceFormat) obj;
|
||||
if (limits.length != cf.limits.length)
|
||||
return false;
|
||||
for (int i = limits.length - 1; i >= 0; --i)
|
||||
{
|
||||
if (limits[i] != cf.limits[i]
|
||||
|| !strings[i].equals(cf.strings[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public StringBuffer format (long num, StringBuffer appendBuf,
|
||||
FieldPosition pos)
|
||||
{
|
||||
return format ((double) num, appendBuf, pos);
|
||||
}
|
||||
|
||||
public StringBuffer format (double num, StringBuffer appendBuf,
|
||||
FieldPosition pos)
|
||||
{
|
||||
if (limits.length == 0)
|
||||
return appendBuf;
|
||||
|
||||
int index = 0;
|
||||
if (! Double.isNaN(num) && num >= limits[0])
|
||||
{
|
||||
for (; index < limits.length - 1; ++index)
|
||||
{
|
||||
if (limits[index] <= num
|
||||
&& index != limits.length - 2
|
||||
&& num < limits[index + 1])
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return appendBuf.append(strings[index]);
|
||||
}
|
||||
|
||||
public Object[] getFormats ()
|
||||
{
|
||||
return (Object[]) strings.clone();
|
||||
}
|
||||
|
||||
public double[] getLimits ()
|
||||
{
|
||||
return (double[]) limits.clone();
|
||||
}
|
||||
|
||||
public int hashCode ()
|
||||
{
|
||||
int hash = 0;
|
||||
for (int i = 0; i < limits.length; ++i)
|
||||
{
|
||||
long v = Double.doubleToLongBits(limits[i]);
|
||||
hash ^= (v ^ (v >>> 32));
|
||||
hash ^= strings[i].hashCode();
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
public static final double nextDouble (double d)
|
||||
{
|
||||
return nextDouble (d, true);
|
||||
}
|
||||
|
||||
public static final double nextDouble (double d, boolean next)
|
||||
{
|
||||
if (Double.isInfinite(d) || Double.isNaN(d))
|
||||
return d;
|
||||
|
||||
long bits = Double.doubleToLongBits(d);
|
||||
|
||||
long mantMask = (1L << mantissaBits) - 1;
|
||||
long mantissa = bits & mantMask;
|
||||
|
||||
long expMask = (1L << exponentBits) - 1;
|
||||
long exponent = (bits >>> mantissaBits) & expMask;
|
||||
|
||||
if (next ^ (bits < 0)) // Increment magnitude
|
||||
{
|
||||
if (mantissa == (1L << mantissaBits) - 1)
|
||||
{
|
||||
mantissa = 0L;
|
||||
exponent++;
|
||||
|
||||
// Check for absolute overflow.
|
||||
if (exponent >= (1L << mantissaBits))
|
||||
return (bits > 0) ? Double.POSITIVE_INFINITY
|
||||
: Double.NEGATIVE_INFINITY;
|
||||
}
|
||||
else
|
||||
mantissa++;
|
||||
}
|
||||
else // Decrement magnitude
|
||||
{
|
||||
if (exponent == 0L && mantissa == 0L)
|
||||
{
|
||||
// The only case where there is a change of sign
|
||||
return next ? Double.MIN_VALUE : -Double.MIN_VALUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mantissa == 0L)
|
||||
{
|
||||
mantissa = (1L << mantissaBits) - 1;
|
||||
exponent--;
|
||||
}
|
||||
else
|
||||
mantissa--;
|
||||
}
|
||||
}
|
||||
|
||||
long result = bits < 0 ? 1 : 0;
|
||||
result = (result << exponentBits) | exponent;
|
||||
result = (result << mantissaBits) | mantissa;
|
||||
return Double.longBitsToDouble(result);
|
||||
}
|
||||
|
||||
public Number parse (String sourceStr, ParsePosition pos)
|
||||
{
|
||||
int index = pos.getIndex();
|
||||
for (int i = 0; i < limits.length; ++i)
|
||||
{
|
||||
if (sourceStr.startsWith(strings[i], index))
|
||||
{
|
||||
pos.setIndex(index + strings[i].length());
|
||||
return new Double (limits[i]);
|
||||
}
|
||||
}
|
||||
pos.setErrorIndex(index);
|
||||
return new Double (Double.NaN);
|
||||
}
|
||||
|
||||
public static final double previousDouble (double d)
|
||||
{
|
||||
return nextDouble (d, false);
|
||||
}
|
||||
|
||||
public void setChoices (double[] limits, String[] strings)
|
||||
{
|
||||
if (limits == null || strings == null)
|
||||
throw new NullPointerException ();
|
||||
if (limits.length != strings.length)
|
||||
throw new IllegalArgumentException ();
|
||||
this.strings = (String[]) strings.clone();
|
||||
this.limits = (double[]) limits.clone();
|
||||
}
|
||||
|
||||
private final void quoteString (StringBuffer dest, String text)
|
||||
{
|
||||
int max = text.length();
|
||||
for (int i = 0; i < max; ++i)
|
||||
{
|
||||
char c = text.charAt(i);
|
||||
if (c == '\'')
|
||||
{
|
||||
dest.append(c);
|
||||
dest.append(c);
|
||||
}
|
||||
else if (c == '#' || c == '|' || c == '\u2064' || c == '<')
|
||||
{
|
||||
dest.append('\'');
|
||||
dest.append(c);
|
||||
dest.append('\'');
|
||||
}
|
||||
else
|
||||
dest.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
public String toPattern ()
|
||||
{
|
||||
StringBuffer result = new StringBuffer ();
|
||||
for (int i = 0; i < limits.length; ++i)
|
||||
{
|
||||
result.append(limits[i]);
|
||||
result.append('#');
|
||||
quoteString (result, strings[i]);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
// Formats and limits.
|
||||
private String[] strings;
|
||||
private double[] limits;
|
||||
|
||||
// Number of mantissa bits in double.
|
||||
private static final int mantissaBits = 52;
|
||||
// Number of exponent bits in a double.
|
||||
private static final int exponentBits = 11;
|
||||
}
|
301
libjava/java/text/DateFormat.java
Normal file
301
libjava/java/text/DateFormat.java
Normal file
|
@ -0,0 +1,301 @@
|
|||
/* Copyright (C) 1998, 1999 Cygnus Solutions
|
||||
|
||||
This file is part of libgcj.
|
||||
|
||||
This software is copyrighted work licensed under the terms of the
|
||||
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
||||
details. */
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Per Bothner <bothner@cygnus.com>
|
||||
* @date October 25, 1998.
|
||||
*/
|
||||
/* Written using "Java Class Libraries", 2nd edition, plus online
|
||||
* API docs for JDK 1.2 beta from http://www.javasoft.com.
|
||||
* Status: Mostly complete; search for FIXME to see omissions.
|
||||
*/
|
||||
|
||||
public abstract class DateFormat extends Format implements Cloneable
|
||||
{
|
||||
protected Calendar calendar;
|
||||
protected NumberFormat numberFormat;
|
||||
|
||||
// (Values determined using a test program.)
|
||||
public final static int FULL = 0;
|
||||
public final static int LONG = 1;
|
||||
public final static int MEDIUM = 2;
|
||||
public final static int SHORT = 3;
|
||||
public final static int DEFAULT = MEDIUM;
|
||||
|
||||
public final static int ERA_FIELD = 0;
|
||||
public final static int YEAR_FIELD = 1;
|
||||
public final static int MONTH_FIELD = 2;
|
||||
public final static int DATE_FIELD = 3;
|
||||
public final static int HOUR_OF_DAY1_FIELD = 4;
|
||||
public final static int HOUR_OF_DAY0_FIELD = 5;
|
||||
public final static int MINUTE_FIELD = 6;
|
||||
public final static int SECOND_FIELD = 7;
|
||||
public final static int MILLISECOND_FIELD = 8;
|
||||
public final static int DAY_OF_WEEK_FIELD = 9;
|
||||
public final static int DAY_OF_YEAR_FIELD = 10;
|
||||
public final static int DAY_OF_WEEK_IN_MONTH_FIELD = 11;
|
||||
public final static int WEEK_OF_YEAR_FIELD = 12;
|
||||
public final static int WEEK_OF_MONTH_FIELD = 13;
|
||||
public final static int AM_PM_FIELD = 14;
|
||||
public final static int HOUR1_FIELD = 15;
|
||||
public final static int HOUR0_FIELD = 16;
|
||||
public final static int TIMEZONE_FIELD = 17;
|
||||
|
||||
protected DateFormat ()
|
||||
{
|
||||
}
|
||||
|
||||
public boolean equals (Object obj)
|
||||
{
|
||||
if (! (obj instanceof DateFormat))
|
||||
return false;
|
||||
DateFormat d = (DateFormat) obj;
|
||||
return calendar.equals(d.calendar) && numberFormat.equals(d.numberFormat);
|
||||
}
|
||||
|
||||
public final StringBuffer format (Object obj,
|
||||
StringBuffer buf, FieldPosition pos)
|
||||
{
|
||||
if (obj instanceof Number)
|
||||
return format (new Date(((Number) obj).longValue()), buf, pos);
|
||||
return format ((Date) obj, buf, pos);
|
||||
}
|
||||
|
||||
public final String format (Date date)
|
||||
{
|
||||
StringBuffer sb = new StringBuffer ();
|
||||
format (date, sb, new FieldPosition (MONTH_FIELD));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public abstract StringBuffer format (Date date,
|
||||
StringBuffer buf, FieldPosition pos);
|
||||
|
||||
public static Locale[] getAvailableLocales ()
|
||||
{
|
||||
return null; // FIXME
|
||||
}
|
||||
|
||||
public Calendar getCalendar ()
|
||||
{
|
||||
return calendar;
|
||||
}
|
||||
|
||||
private static final DateFormat computeInstance (int style, Locale loc,
|
||||
boolean use_date,
|
||||
boolean use_time)
|
||||
{
|
||||
ResourceBundle res;
|
||||
try
|
||||
{
|
||||
res = ResourceBundle.getBundle("gnu.gcj.text.LocaleData", loc);
|
||||
}
|
||||
catch (MissingResourceException x)
|
||||
{
|
||||
res = null;
|
||||
}
|
||||
|
||||
String pattern = null;
|
||||
if (use_date)
|
||||
{
|
||||
String name, def;
|
||||
switch (style)
|
||||
{
|
||||
case FULL:
|
||||
name = "fullDateFormat";
|
||||
def = "EEEE MMMM d, yyyy G";
|
||||
break;
|
||||
case LONG:
|
||||
name = "longDateFormat";
|
||||
def = "MMMM d, yyyy";
|
||||
break;
|
||||
case MEDIUM:
|
||||
name = "mediumDateFormat";
|
||||
def = "d-MMM-yy";
|
||||
break;
|
||||
case SHORT:
|
||||
name = "shortDateFormat";
|
||||
def = "M/d/yy";
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException ();
|
||||
}
|
||||
try
|
||||
{
|
||||
pattern = res == null ? def : res.getString(name);
|
||||
}
|
||||
catch (MissingResourceException x)
|
||||
{
|
||||
pattern = def;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_time)
|
||||
{
|
||||
if (pattern == null)
|
||||
pattern = "";
|
||||
else
|
||||
pattern += " ";
|
||||
|
||||
String name, def;
|
||||
switch (style)
|
||||
{
|
||||
case FULL:
|
||||
name = "fullTimeFormat";
|
||||
def = "h:mm:ss;S 'o''clock' a z";
|
||||
break;
|
||||
case LONG:
|
||||
name = "longTimeFormat";
|
||||
def = "h:mm:ss a z";
|
||||
break;
|
||||
case MEDIUM:
|
||||
name = "mediumTimeFormat";
|
||||
def = "h:mm:ss a";
|
||||
break;
|
||||
case SHORT:
|
||||
name = "shortTimeFormat";
|
||||
def = "h:mm a";
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException ();
|
||||
}
|
||||
|
||||
String s;
|
||||
try
|
||||
{
|
||||
s = res == null ? def : res.getString(name);
|
||||
}
|
||||
catch (MissingResourceException x)
|
||||
{
|
||||
s = def;
|
||||
}
|
||||
pattern += s;
|
||||
}
|
||||
|
||||
return new SimpleDateFormat (pattern, loc);
|
||||
}
|
||||
|
||||
public static final DateFormat getDateInstance ()
|
||||
{
|
||||
return getDateInstance (DEFAULT, Locale.getDefault());
|
||||
}
|
||||
|
||||
public static final DateFormat getDateInstance (int style)
|
||||
{
|
||||
return getDateInstance (style, Locale.getDefault());
|
||||
}
|
||||
|
||||
public static final DateFormat getDateInstance (int style, Locale loc)
|
||||
{
|
||||
return computeInstance (style, loc, true, false);
|
||||
}
|
||||
|
||||
public static final DateFormat getDateTimeInstance ()
|
||||
{
|
||||
return getDateTimeInstance (DEFAULT, Locale.getDefault());
|
||||
}
|
||||
|
||||
public static final DateFormat getDateTimeInstance (int style)
|
||||
{
|
||||
return getDateTimeInstance (style, Locale.getDefault());
|
||||
}
|
||||
|
||||
public static final DateFormat getDateTimeInstance (int style, Locale loc)
|
||||
{
|
||||
return computeInstance (style, loc, true, true);
|
||||
}
|
||||
|
||||
public static final DateFormat getInstance ()
|
||||
{
|
||||
// JCL book says SHORT.
|
||||
return getDateTimeInstance (SHORT, Locale.getDefault());
|
||||
}
|
||||
|
||||
public NumberFormat getNumberFormat ()
|
||||
{
|
||||
return numberFormat;
|
||||
}
|
||||
|
||||
public static final DateFormat getTimeInstance ()
|
||||
{
|
||||
return getTimeInstance (DEFAULT, Locale.getDefault());
|
||||
}
|
||||
|
||||
public static final DateFormat getTimeInstance (int style)
|
||||
{
|
||||
return getTimeInstance (style, Locale.getDefault());
|
||||
}
|
||||
|
||||
public static final DateFormat getTimeInstance (int style, Locale loc)
|
||||
{
|
||||
return computeInstance (style, loc, false, true);
|
||||
}
|
||||
|
||||
public TimeZone getTimeZone ()
|
||||
{
|
||||
return calendar.getTimeZone();
|
||||
}
|
||||
|
||||
public int hashCode ()
|
||||
{
|
||||
int hash = calendar.hashCode();
|
||||
if (numberFormat != null)
|
||||
hash ^= numberFormat.hashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
public boolean isLenient ()
|
||||
{
|
||||
return calendar.isLenient();
|
||||
}
|
||||
|
||||
public Date parse (String source) throws ParseException
|
||||
{
|
||||
ParsePosition pos = new ParsePosition(0);
|
||||
Date result = parse (source, pos);
|
||||
if (result == null)
|
||||
{
|
||||
int index = pos.getErrorIndex();
|
||||
if (index < 0)
|
||||
index = pos.getIndex();
|
||||
throw new ParseException("invalid Date syntax", index);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public abstract Date parse (String source, ParsePosition pos);
|
||||
|
||||
public Object parseObject (String source, ParsePosition pos)
|
||||
{
|
||||
return parse(source, pos);
|
||||
}
|
||||
|
||||
public void setCalendar (Calendar calendar)
|
||||
{
|
||||
this.calendar = calendar;
|
||||
}
|
||||
|
||||
public void setLenient (boolean lenient)
|
||||
{
|
||||
calendar.setLenient(lenient);
|
||||
}
|
||||
|
||||
public void setNumberFormat (NumberFormat numberFormat)
|
||||
{
|
||||
this.numberFormat = numberFormat;
|
||||
}
|
||||
|
||||
public void setTimeZone (TimeZone timeZone)
|
||||
{
|
||||
calendar.setTimeZone(timeZone);
|
||||
}
|
||||
}
|
265
libjava/java/text/DateFormatSymbols.java
Normal file
265
libjava/java/text/DateFormatSymbols.java
Normal file
|
@ -0,0 +1,265 @@
|
|||
/* Copyright (C) 1998, 1999 Cygnus Solutions
|
||||
|
||||
This file is part of libgcj.
|
||||
|
||||
This software is copyrighted work licensed under the terms of the
|
||||
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
||||
details. */
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* @author Per Bothner <bothner@cygnus.com>
|
||||
* @date October 24, 1998.
|
||||
*/
|
||||
|
||||
/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3.
|
||||
* Status: Believed complete and correct.
|
||||
*/
|
||||
|
||||
public class DateFormatSymbols extends Object
|
||||
implements java.io.Serializable, Cloneable
|
||||
{
|
||||
private String[] ampms;
|
||||
private String[] eras;
|
||||
private String localPatternChars;
|
||||
private String[] months;
|
||||
private String[] shortMonths;
|
||||
private String[] shortWeekdays;
|
||||
private String[] weekdays;
|
||||
private String[][] zoneStrings;
|
||||
|
||||
private static final String[] ampmsDefault = {"AM", "PM" };
|
||||
private static final String[] erasDefault = {"BC", "AD" };
|
||||
// localPatternCharsDefault is used by SimpleDateFormat.
|
||||
protected static final String localPatternCharsDefault
|
||||
= "GyMdkHmsSEDFwWahKz";
|
||||
private static final String[] monthsDefault = {
|
||||
"January", "February", "March", "April", "May", "June",
|
||||
"July", "August", "September", "October", "November", "December", ""
|
||||
};
|
||||
private static final String[] shortMonthsDefault = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""
|
||||
};
|
||||
private static final String[] shortWeekdaysDefault = {
|
||||
"", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
|
||||
};
|
||||
private static final String[] weekdaysDefault = {
|
||||
"", "Sunday", "Monday", "Tuesday",
|
||||
"Wednesday", "Thursday", "Friday", "Saturday"
|
||||
};
|
||||
|
||||
private static String[][] zoneStringsDefault = {
|
||||
{ "PST", "Pacific Standard Time", "PST",
|
||||
/**/ "Pacific Daylight Time", "PDT", "San Francisco" },
|
||||
{ "MST", "Mountain Standard Time", "MST",
|
||||
/**/ "Mountain Daylight Time", "MDT", "Denver" },
|
||||
{ "PNT", "Mountain Standard Time", "MST",
|
||||
/**/ "Mountain Standard Time", "MST", "Phoenix" },
|
||||
{ "CST", "Central Standard Time", "CST",
|
||||
/**/ "Central Daylight Time", "CDT", "Chicago" },
|
||||
{ "EST", "Eastern Standard Time", "EST",
|
||||
/**/ "Eastern Daylight Time", "EDT", "Boston" },
|
||||
{ "IET", "Eastern Standard Time", "EST",
|
||||
/**/ "Eastern Standard Time", "EST", "Indianapolis" },
|
||||
{ "PRT", "Atlantic Standard Time", "AST",
|
||||
/**/ "Atlantic Daylight Time", "ADT", "Halifax" },
|
||||
{ "HST", "Hawaii Standard Time", "HST",
|
||||
/**/ "Hawaii Daylight Time", "HDT", "Honolulu" },
|
||||
{ "AST", "Alaska Standard Time", "AST",
|
||||
/**/ "Alaska Daylight Time", "ADT", "Anchorage" }
|
||||
};
|
||||
|
||||
private final Object safeGetResource (ResourceBundle res,
|
||||
String key, Object def)
|
||||
{
|
||||
if (res != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return res.getObject(key);
|
||||
}
|
||||
catch (MissingResourceException x)
|
||||
{
|
||||
}
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
public DateFormatSymbols (Locale locale)
|
||||
{
|
||||
ResourceBundle res;
|
||||
try
|
||||
{
|
||||
res = ResourceBundle.getBundle("gnu.gcj.text.LocaleData", locale);
|
||||
}
|
||||
catch (MissingResourceException x)
|
||||
{
|
||||
res = null;
|
||||
}
|
||||
ampms = (String[]) safeGetResource (res, "ampm", ampmsDefault);
|
||||
eras = (String[]) safeGetResource (res, "eras", erasDefault);
|
||||
localPatternChars = (String) safeGetResource (res, "datePatternChars",
|
||||
localPatternCharsDefault);
|
||||
months = (String[]) safeGetResource (res, "months", monthsDefault);
|
||||
shortMonths = (String[]) safeGetResource (res, "shortMonths",
|
||||
shortMonthsDefault);
|
||||
shortWeekdays = (String[]) safeGetResource (res, "shortWeekdays",
|
||||
shortWeekdaysDefault);
|
||||
weekdays = (String[]) safeGetResource (res, "weekdays", weekdaysDefault);
|
||||
zoneStrings = (String[][]) safeGetResource (res, "zoneStrings",
|
||||
zoneStringsDefault);
|
||||
}
|
||||
|
||||
public DateFormatSymbols ()
|
||||
{
|
||||
this (Locale.getDefault());
|
||||
}
|
||||
|
||||
public String[] getAmPmStrings()
|
||||
{
|
||||
return ampms;
|
||||
}
|
||||
|
||||
public String[] getEras()
|
||||
{
|
||||
return eras;
|
||||
}
|
||||
|
||||
|
||||
public String getLocalPatternChars()
|
||||
{
|
||||
return localPatternChars;
|
||||
}
|
||||
|
||||
public String[] getMonths ()
|
||||
{
|
||||
return months;
|
||||
}
|
||||
|
||||
public String[] getShortMonths ()
|
||||
{
|
||||
return shortMonths;
|
||||
}
|
||||
|
||||
public String[] getShortWeekdays ()
|
||||
{
|
||||
return shortWeekdays;
|
||||
}
|
||||
|
||||
public String[] getWeekdays ()
|
||||
{
|
||||
return weekdays;
|
||||
}
|
||||
|
||||
public String[] [] getZoneStrings ()
|
||||
{
|
||||
return zoneStrings;
|
||||
}
|
||||
|
||||
public void setAmPmStrings (String[] value)
|
||||
{
|
||||
ampms = value;
|
||||
}
|
||||
|
||||
public void setEras (String[] value)
|
||||
{
|
||||
eras = value;
|
||||
}
|
||||
|
||||
public void setLocalPatternChars (String value)
|
||||
{
|
||||
localPatternChars = value;
|
||||
}
|
||||
|
||||
public void setMonths (String[] value)
|
||||
{
|
||||
months = value;
|
||||
}
|
||||
|
||||
public void setShortMonths (String[] value)
|
||||
{
|
||||
shortMonths = value;
|
||||
}
|
||||
|
||||
public void setShortWeekdays (String[] value)
|
||||
{
|
||||
shortWeekdays = value;
|
||||
}
|
||||
|
||||
public void setWeekdays (String[] value)
|
||||
{
|
||||
weekdays = value;
|
||||
}
|
||||
|
||||
public void setZoneStrings (String[][] value)
|
||||
{
|
||||
zoneStrings = value;
|
||||
}
|
||||
|
||||
/* Does a "deep" equality test - recurses into arrays. */
|
||||
protected static boolean equals (Object x, Object y)
|
||||
{
|
||||
if (x == y)
|
||||
return true;
|
||||
if (x == null || y == null)
|
||||
return false;
|
||||
if (! (x instanceof Object[]) || ! (y instanceof Object[]))
|
||||
return x.equals(y);
|
||||
Object[] xa = (Object[]) x;
|
||||
Object[] ya = (Object[]) y;
|
||||
if (xa.length != ya.length)
|
||||
return false;
|
||||
for (int i = xa.length; --i >= 0; )
|
||||
{
|
||||
if (! equals(xa[i], ya[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int hashCode (Object x)
|
||||
{
|
||||
if (x == null)
|
||||
return 0;
|
||||
if (! (x instanceof Object[]))
|
||||
return x.hashCode();
|
||||
Object[] xa = (Object[]) x;
|
||||
int hash = 0;
|
||||
for (int i = 0; i < xa.length; i++)
|
||||
hash = 37 * hashCode(xa[i]);
|
||||
return hash;
|
||||
}
|
||||
|
||||
public boolean equals (Object obj)
|
||||
{
|
||||
if (obj == null || ! (obj instanceof DateFormatSymbols))
|
||||
return false;
|
||||
DateFormatSymbols other = (DateFormatSymbols) obj;
|
||||
return (equals(ampms, other.ampms)
|
||||
&& equals(eras, other.eras)
|
||||
&& equals(localPatternChars, other.localPatternChars)
|
||||
&& equals(months, other.months)
|
||||
&& equals(shortMonths, other.shortMonths)
|
||||
&& equals(shortWeekdays, other.shortWeekdays)
|
||||
&& equals(weekdays, other.weekdays)
|
||||
&& equals(zoneStrings, other.zoneStrings));
|
||||
}
|
||||
|
||||
public int hashCode ()
|
||||
{
|
||||
return (hashCode(ampms)
|
||||
^ hashCode(eras)
|
||||
^ hashCode(localPatternChars)
|
||||
^ hashCode(months)
|
||||
^ hashCode(shortMonths)
|
||||
^ hashCode(shortWeekdays)
|
||||
^ hashCode(weekdays)
|
||||
^ hashCode(zoneStrings));
|
||||
}
|
||||
}
|
983
libjava/java/text/DecimalFormat.java
Normal file
983
libjava/java/text/DecimalFormat.java
Normal file
|
@ -0,0 +1,983 @@
|
|||
// DecimalFormat.java - Localized number formatting.
|
||||
|
||||
/* Copyright (C) 1999 Cygnus Solutions
|
||||
|
||||
This file is part of libgcj.
|
||||
|
||||
This software is copyrighted work licensed under the terms of the
|
||||
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
||||
details. */
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* @author Tom Tromey <tromey@cygnus.com>
|
||||
* @date March 4, 1999
|
||||
*/
|
||||
/* Written using "Java Class Libraries", 2nd edition, plus online
|
||||
* API docs for JDK 1.2 from http://www.javasoft.com.
|
||||
* Status: Believed complete and correct to 1.2, except serialization.
|
||||
* Note however that the docs are very unclear about how format parsing
|
||||
* should work. No doubt there are problems here.
|
||||
*/
|
||||
|
||||
public class DecimalFormat extends NumberFormat
|
||||
{
|
||||
// This is a helper for applyPatternWithSymbols. It reads a prefix
|
||||
// or a suffix. It can cause some side-effects.
|
||||
private final int scanFix (String pattern, int index, StringBuffer buf,
|
||||
String patChars, DecimalFormatSymbols syms,
|
||||
boolean is_suffix)
|
||||
throws ParseException
|
||||
{
|
||||
int len = pattern.length();
|
||||
buf.setLength(0);
|
||||
boolean multiplierSet = false;
|
||||
while (index < len)
|
||||
{
|
||||
char c = pattern.charAt(index);
|
||||
if (c == '\'' && index + 1 < len
|
||||
&& pattern.charAt(index + 1) == '\'')
|
||||
{
|
||||
buf.append(c);
|
||||
++index;
|
||||
}
|
||||
else if (c == '\'' && index + 2 < len
|
||||
&& pattern.charAt(index + 2) == '\'')
|
||||
{
|
||||
buf.append(pattern.charAt(index + 1));
|
||||
index += 2;
|
||||
}
|
||||
else if (c == '\u00a4')
|
||||
{
|
||||
if (index + 1 < len && pattern.charAt(index + 1) == '\u00a4')
|
||||
{
|
||||
buf.append(syms.getInternationalCurrencySymbol());
|
||||
++index;
|
||||
}
|
||||
else
|
||||
buf.append(syms.getCurrencySymbol());
|
||||
}
|
||||
else if (is_suffix && c == syms.getPercent())
|
||||
{
|
||||
if (multiplierSet)
|
||||
throw new ParseException ("multiplier already set", index);
|
||||
multiplierSet = true;
|
||||
multiplier = 100;
|
||||
buf.append(c);
|
||||
}
|
||||
else if (is_suffix && c == syms.getPerMill())
|
||||
{
|
||||
if (multiplierSet)
|
||||
throw new ParseException ("multiplier already set", index);
|
||||
multiplierSet = true;
|
||||
multiplier = 1000;
|
||||
buf.append(c);
|
||||
}
|
||||
else if (patChars.indexOf(c) != -1)
|
||||
{
|
||||
// This is a pattern character.
|
||||
break;
|
||||
}
|
||||
else
|
||||
buf.append(c);
|
||||
++index;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
// A helper which reads a number format.
|
||||
private final int scanFormat (String pattern, int index,
|
||||
String patChars, DecimalFormatSymbols syms,
|
||||
boolean is_positive)
|
||||
throws ParseException
|
||||
{
|
||||
int max = pattern.length();
|
||||
|
||||
int countSinceGroup = 0;
|
||||
int zeroCount = 0;
|
||||
boolean saw_group = false;
|
||||
|
||||
//
|
||||
// Scan integer part.
|
||||
//
|
||||
while (index < max)
|
||||
{
|
||||
char c = pattern.charAt(index);
|
||||
|
||||
if (c == syms.getDigit())
|
||||
{
|
||||
if (zeroCount > 0)
|
||||
throw new ParseException ("digit mark following zero", index);
|
||||
++countSinceGroup;
|
||||
}
|
||||
else if (c == syms.getZeroDigit())
|
||||
{
|
||||
++zeroCount;
|
||||
++countSinceGroup;
|
||||
}
|
||||
else if (c == syms.getGroupingSeparator())
|
||||
{
|
||||
countSinceGroup = 0;
|
||||
saw_group = true;
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
++index;
|
||||
}
|
||||
|
||||
// We can only side-effect when parsing the positive format.
|
||||
if (is_positive)
|
||||
{
|
||||
groupingUsed = saw_group;
|
||||
groupingSize = (byte) countSinceGroup;
|
||||
minimumIntegerDigits = zeroCount;
|
||||
}
|
||||
|
||||
// Early termination.
|
||||
if (index == max || pattern.charAt(index) == syms.getGroupingSeparator())
|
||||
{
|
||||
if (is_positive)
|
||||
decimalSeparatorAlwaysShown = false;
|
||||
return index;
|
||||
}
|
||||
|
||||
if (pattern.charAt(index) == syms.getDecimalSeparator())
|
||||
{
|
||||
++index;
|
||||
|
||||
//
|
||||
// Scan fractional part.
|
||||
//
|
||||
int hashCount = 0;
|
||||
zeroCount = 0;
|
||||
while (index < max)
|
||||
{
|
||||
char c = pattern.charAt(index);
|
||||
if (c == syms.getZeroDigit())
|
||||
{
|
||||
if (hashCount > 0)
|
||||
throw new ParseException ("zero mark following digit",
|
||||
index);
|
||||
++zeroCount;
|
||||
}
|
||||
else if (c == syms.getDigit())
|
||||
{
|
||||
++hashCount;
|
||||
}
|
||||
else if (c != syms.getExponential()
|
||||
&& c != syms.getPatternSeparator()
|
||||
&& patChars.indexOf(c) != -1)
|
||||
throw new ParseException ("unexpected special character",
|
||||
index);
|
||||
else
|
||||
break;
|
||||
|
||||
++index;
|
||||
}
|
||||
|
||||
if (is_positive)
|
||||
{
|
||||
maximumFractionDigits = hashCount + zeroCount;
|
||||
minimumFractionDigits = zeroCount;
|
||||
}
|
||||
|
||||
if (index == max)
|
||||
return index;
|
||||
}
|
||||
|
||||
if (pattern.charAt(index) == syms.getExponential())
|
||||
{
|
||||
//
|
||||
// Scan exponential format.
|
||||
//
|
||||
zeroCount = 0;
|
||||
++index;
|
||||
while (index < max)
|
||||
{
|
||||
char c = pattern.charAt(index);
|
||||
if (c == syms.getZeroDigit())
|
||||
++zeroCount;
|
||||
else if (c == syms.getDigit())
|
||||
{
|
||||
if (zeroCount > 0)
|
||||
throw new
|
||||
ParseException ("digit mark following zero in exponent",
|
||||
index);
|
||||
}
|
||||
else if (patChars.indexOf(c) != -1)
|
||||
throw new ParseException ("unexpected special character",
|
||||
index);
|
||||
else
|
||||
break;
|
||||
|
||||
++index;
|
||||
}
|
||||
|
||||
if (is_positive)
|
||||
{
|
||||
useExponentialNotation = true;
|
||||
minExponentDigits = (byte) zeroCount;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
// This helper function creates a string consisting of all the
|
||||
// characters which can appear in a pattern and must be quoted.
|
||||
private final String patternChars (DecimalFormatSymbols syms)
|
||||
{
|
||||
StringBuffer buf = new StringBuffer ();
|
||||
buf.append(syms.getDecimalSeparator());
|
||||
buf.append(syms.getDigit());
|
||||
buf.append(syms.getExponential());
|
||||
buf.append(syms.getGroupingSeparator());
|
||||
// Adding this one causes pattern application to fail.
|
||||
// Of course, omitting is causes toPattern to fail.
|
||||
// ... but we already have bugs there. FIXME.
|
||||
// buf.append(syms.getMinusSign());
|
||||
buf.append(syms.getPatternSeparator());
|
||||
buf.append(syms.getPercent());
|
||||
buf.append(syms.getPerMill());
|
||||
buf.append(syms.getZeroDigit());
|
||||
buf.append('\u00a4');
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private final void applyPatternWithSymbols (String pattern,
|
||||
DecimalFormatSymbols syms)
|
||||
throws ParseException
|
||||
{
|
||||
// Initialize to the state the parser expects.
|
||||
negativePrefix = "";
|
||||
negativeSuffix = "";
|
||||
positivePrefix = "";
|
||||
positiveSuffix = "";
|
||||
decimalSeparatorAlwaysShown = false;
|
||||
groupingSize = 0;
|
||||
minExponentDigits = 0;
|
||||
multiplier = 1;
|
||||
useExponentialNotation = false;
|
||||
groupingUsed = false;
|
||||
maximumFractionDigits = 0;
|
||||
maximumIntegerDigits = 309;
|
||||
minimumFractionDigits = 0;
|
||||
minimumIntegerDigits = 1;
|
||||
|
||||
StringBuffer buf = new StringBuffer ();
|
||||
String patChars = patternChars (syms);
|
||||
|
||||
int max = pattern.length();
|
||||
int index = scanFix (pattern, 0, buf, patChars, syms, false);
|
||||
positivePrefix = buf.toString();
|
||||
|
||||
index = scanFormat (pattern, index, patChars, syms, true);
|
||||
|
||||
index = scanFix (pattern, index, buf, patChars, syms, true);
|
||||
positiveSuffix = buf.toString();
|
||||
|
||||
if (index == pattern.length())
|
||||
{
|
||||
// No negative info.
|
||||
negativePrefix = null;
|
||||
negativeSuffix = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pattern.charAt(index) != syms.getPatternSeparator())
|
||||
throw new ParseException ("separator character expected", index);
|
||||
|
||||
index = scanFix (pattern, index + 1, buf, patChars, syms, false);
|
||||
negativePrefix = buf.toString();
|
||||
|
||||
// We parse the negative format for errors but we don't let
|
||||
// it side-effect this object.
|
||||
index = scanFormat (pattern, index, patChars, syms, false);
|
||||
|
||||
index = scanFix (pattern, index, buf, patChars, syms, true);
|
||||
negativeSuffix = buf.toString();
|
||||
|
||||
if (index != pattern.length())
|
||||
throw new ParseException ("end of pattern expected", index);
|
||||
}
|
||||
}
|
||||
|
||||
public void applyLocalizedPattern (String pattern) throws ParseException
|
||||
{
|
||||
applyPatternWithSymbols (pattern, symbols);
|
||||
}
|
||||
|
||||
public void applyPattern (String pattern) throws ParseException
|
||||
{
|
||||
applyPatternWithSymbols (pattern, nonLocalizedSymbols);
|
||||
}
|
||||
|
||||
public Object clone ()
|
||||
{
|
||||
return new DecimalFormat (this);
|
||||
}
|
||||
|
||||
private DecimalFormat (DecimalFormat dup)
|
||||
{
|
||||
decimalSeparatorAlwaysShown = dup.decimalSeparatorAlwaysShown;
|
||||
groupingSize = dup.groupingSize;
|
||||
minExponentDigits = dup.minExponentDigits;
|
||||
multiplier = dup.multiplier;
|
||||
negativePrefix = dup.negativePrefix;
|
||||
negativeSuffix = dup.negativeSuffix;
|
||||
positivePrefix = dup.positivePrefix;
|
||||
positiveSuffix = dup.positiveSuffix;
|
||||
symbols = (DecimalFormatSymbols) dup.symbols.clone();
|
||||
useExponentialNotation = dup.useExponentialNotation;
|
||||
}
|
||||
|
||||
public DecimalFormat ()
|
||||
{
|
||||
this ("#,##0.###");
|
||||
}
|
||||
|
||||
public DecimalFormat (String pattern)
|
||||
{
|
||||
this (pattern, new DecimalFormatSymbols ());
|
||||
}
|
||||
|
||||
public DecimalFormat (String pattern, DecimalFormatSymbols symbols)
|
||||
{
|
||||
this.symbols = symbols;
|
||||
// The docs imply that the constructor turns a ParseException
|
||||
// into an IllegalArgumentException.
|
||||
try
|
||||
{
|
||||
applyPattern (pattern);
|
||||
}
|
||||
catch (ParseException x)
|
||||
{
|
||||
throw new IllegalArgumentException (x.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private final boolean equals (String s1, String s2)
|
||||
{
|
||||
if (s1 == null || s2 == null)
|
||||
return s1 == s2;
|
||||
return s1.equals(s2);
|
||||
}
|
||||
|
||||
public boolean equals (Object obj)
|
||||
{
|
||||
if (! (obj instanceof DecimalFormat))
|
||||
return false;
|
||||
DecimalFormat dup = (DecimalFormat) obj;
|
||||
return (decimalSeparatorAlwaysShown == dup.decimalSeparatorAlwaysShown
|
||||
&& groupingSize == dup.groupingSize
|
||||
&& minExponentDigits == dup.minExponentDigits
|
||||
&& multiplier == dup.multiplier
|
||||
&& equals(negativePrefix, dup.negativePrefix)
|
||||
&& equals(negativeSuffix, dup.negativeSuffix)
|
||||
&& equals(positivePrefix, dup.positivePrefix)
|
||||
&& equals(positiveSuffix, dup.positiveSuffix)
|
||||
&& symbols.equals(dup.symbols)
|
||||
&& useExponentialNotation == dup.useExponentialNotation);
|
||||
}
|
||||
|
||||
public StringBuffer format (double number, StringBuffer dest,
|
||||
FieldPosition fieldPos)
|
||||
{
|
||||
// A very special case.
|
||||
if (Double.isNaN(number))
|
||||
{
|
||||
dest.append(symbols.getNaN());
|
||||
if (fieldPos != null && fieldPos.getField() == INTEGER_FIELD)
|
||||
{
|
||||
int index = dest.length();
|
||||
fieldPos.setBeginIndex(index - symbols.getNaN().length());
|
||||
fieldPos.setEndIndex(index);
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
boolean is_neg = number < 0;
|
||||
if (is_neg)
|
||||
{
|
||||
if (negativePrefix != null)
|
||||
dest.append(negativePrefix);
|
||||
else
|
||||
{
|
||||
dest.append(symbols.getMinusSign());
|
||||
dest.append(positivePrefix);
|
||||
}
|
||||
number = - number;
|
||||
}
|
||||
else
|
||||
dest.append(positivePrefix);
|
||||
|
||||
int integerBeginIndex = dest.length();
|
||||
int integerEndIndex = 0;
|
||||
if (Double.isInfinite (number))
|
||||
{
|
||||
dest.append(symbols.getInfinity());
|
||||
integerEndIndex = dest.length();
|
||||
}
|
||||
else
|
||||
{
|
||||
number *= multiplier;
|
||||
|
||||
// Compute exponent.
|
||||
long exponent = 0;
|
||||
double baseNumber;
|
||||
if (useExponentialNotation)
|
||||
{
|
||||
exponent = (long) (Math.log(number) / Math.log(10));
|
||||
if (minimumIntegerDigits > 0)
|
||||
exponent -= minimumIntegerDigits - 1;
|
||||
baseNumber = (long) (number / Math.pow(10.0, exponent));
|
||||
}
|
||||
else
|
||||
baseNumber = number;
|
||||
|
||||
// Round to the correct number of digits.
|
||||
baseNumber += 5 * Math.pow(10.0, - maximumFractionDigits - 1);
|
||||
|
||||
int index = dest.length();
|
||||
double intPart = Math.floor(baseNumber);
|
||||
int count = 0;
|
||||
while (count < maximumIntegerDigits
|
||||
&& (intPart > 0 || count < minimumIntegerDigits))
|
||||
{
|
||||
long dig = (long) (intPart % 10);
|
||||
intPart = Math.floor(intPart / 10);
|
||||
|
||||
// Append group separator if required.
|
||||
if (groupingUsed && count > 0 && count % groupingSize == 0)
|
||||
dest.insert(index, symbols.getGroupingSeparator());
|
||||
|
||||
dest.insert(index, (char) (symbols.getZeroDigit() + dig));
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
integerEndIndex = dest.length();
|
||||
|
||||
int decimal_index = integerEndIndex;
|
||||
int consecutive_zeros = 0;
|
||||
int total_digits = 0;
|
||||
|
||||
// Strip integer part from NUMBER.
|
||||
double fracPart = baseNumber - Math.floor(baseNumber);
|
||||
for (count = 0;
|
||||
count < maximumFractionDigits
|
||||
&& (fracPart != 0 || count < minimumFractionDigits);
|
||||
++count)
|
||||
{
|
||||
++total_digits;
|
||||
fracPart *= 10;
|
||||
long dig = (long) fracPart;
|
||||
if (dig == 0)
|
||||
++consecutive_zeros;
|
||||
else
|
||||
consecutive_zeros = 0;
|
||||
dest.append((char) (symbols.getZeroDigit() + dig));
|
||||
|
||||
// Strip integer part from FRACPART.
|
||||
fracPart = fracPart - Math.floor (fracPart);
|
||||
}
|
||||
|
||||
// Strip extraneous trailing `0's. We can't always detect
|
||||
// these in the loop.
|
||||
int extra_zeros = Math.min (consecutive_zeros,
|
||||
total_digits - minimumFractionDigits);
|
||||
if (extra_zeros > 0)
|
||||
{
|
||||
dest.setLength(dest.length() - extra_zeros);
|
||||
total_digits -= extra_zeros;
|
||||
}
|
||||
|
||||
// If required, add the decimal symbol.
|
||||
if (decimalSeparatorAlwaysShown
|
||||
|| total_digits > 0)
|
||||
{
|
||||
dest.insert(decimal_index, symbols.getDecimalSeparator());
|
||||
if (fieldPos != null && fieldPos.getField() == FRACTION_FIELD)
|
||||
{
|
||||
fieldPos.setBeginIndex(decimal_index + 1);
|
||||
fieldPos.setEndIndex(dest.length());
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, print the exponent.
|
||||
if (useExponentialNotation)
|
||||
{
|
||||
dest.append(symbols.getExponential());
|
||||
dest.append(exponent < 0 ? '-' : '+');
|
||||
index = dest.length();
|
||||
for (count = 0;
|
||||
exponent > 0 || count < minExponentDigits;
|
||||
++count)
|
||||
{
|
||||
long dig = exponent % 10;
|
||||
exponent /= 10;
|
||||
dest.insert(index, (char) (symbols.getZeroDigit() + dig));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fieldPos != null && fieldPos.getField() == INTEGER_FIELD)
|
||||
{
|
||||
fieldPos.setBeginIndex(integerBeginIndex);
|
||||
fieldPos.setEndIndex(integerEndIndex);
|
||||
}
|
||||
|
||||
dest.append((is_neg && negativeSuffix != null)
|
||||
? negativeSuffix
|
||||
: positiveSuffix);
|
||||
return dest;
|
||||
}
|
||||
|
||||
public StringBuffer format (long number, StringBuffer dest,
|
||||
FieldPosition fieldPos)
|
||||
{
|
||||
// If using exponential notation, we just format as a double.
|
||||
if (useExponentialNotation)
|
||||
return format ((double) number, dest, fieldPos);
|
||||
|
||||
boolean is_neg = number < 0;
|
||||
if (is_neg)
|
||||
{
|
||||
if (negativePrefix != null)
|
||||
dest.append(negativePrefix);
|
||||
else
|
||||
{
|
||||
dest.append(symbols.getMinusSign());
|
||||
dest.append(positivePrefix);
|
||||
}
|
||||
number = - number;
|
||||
}
|
||||
else
|
||||
dest.append(positivePrefix);
|
||||
|
||||
int integerBeginIndex = dest.length();
|
||||
int index = dest.length();
|
||||
int count = 0;
|
||||
while (count < maximumIntegerDigits
|
||||
&& (number > 0 || count < minimumIntegerDigits))
|
||||
{
|
||||
long dig = number % 10;
|
||||
number /= 10;
|
||||
// NUMBER and DIG will be less than 0 if the original number
|
||||
// was the most negative long.
|
||||
if (dig < 0)
|
||||
{
|
||||
dig = - dig;
|
||||
number = - number;
|
||||
}
|
||||
|
||||
// Append group separator if required.
|
||||
if (groupingUsed && count > 0 && count % groupingSize == 0)
|
||||
dest.insert(index, symbols.getGroupingSeparator());
|
||||
|
||||
dest.insert(index, (char) (symbols.getZeroDigit() + dig));
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
if (fieldPos != null && fieldPos.getField() == INTEGER_FIELD)
|
||||
{
|
||||
fieldPos.setBeginIndex(integerBeginIndex);
|
||||
fieldPos.setEndIndex(dest.length());
|
||||
}
|
||||
|
||||
if (decimalSeparatorAlwaysShown || minimumFractionDigits > 0)
|
||||
{
|
||||
dest.append(symbols.getDecimalSeparator());
|
||||
if (fieldPos != null && fieldPos.getField() == FRACTION_FIELD)
|
||||
{
|
||||
fieldPos.setBeginIndex(dest.length());
|
||||
fieldPos.setEndIndex(dest.length() + minimumFractionDigits);
|
||||
}
|
||||
}
|
||||
|
||||
for (count = 0; count < minimumFractionDigits; ++count)
|
||||
dest.append(symbols.getZeroDigit());
|
||||
|
||||
dest.append((is_neg && negativeSuffix != null)
|
||||
? negativeSuffix
|
||||
: positiveSuffix);
|
||||
return dest;
|
||||
}
|
||||
|
||||
public DecimalFormatSymbols getDecimalFormatSymbols ()
|
||||
{
|
||||
return symbols;
|
||||
}
|
||||
|
||||
public int getGroupingSize ()
|
||||
{
|
||||
return groupingSize;
|
||||
}
|
||||
|
||||
public int getMultiplier ()
|
||||
{
|
||||
return multiplier;
|
||||
}
|
||||
|
||||
public String getNegativePrefix ()
|
||||
{
|
||||
return negativePrefix;
|
||||
}
|
||||
|
||||
public String getNegativeSuffix ()
|
||||
{
|
||||
return negativeSuffix;
|
||||
}
|
||||
|
||||
public String getPositivePrefix ()
|
||||
{
|
||||
return positivePrefix;
|
||||
}
|
||||
|
||||
public String getPositiveSuffix ()
|
||||
{
|
||||
return positiveSuffix;
|
||||
}
|
||||
|
||||
public int hashCode ()
|
||||
{
|
||||
int hash = (negativeSuffix.hashCode() ^ negativePrefix.hashCode()
|
||||
^positivePrefix.hashCode() ^ positiveSuffix.hashCode());
|
||||
// FIXME.
|
||||
return hash;
|
||||
}
|
||||
|
||||
public boolean isDecimalSeparatorAlwaysShown ()
|
||||
{
|
||||
return decimalSeparatorAlwaysShown;
|
||||
}
|
||||
|
||||
public Number parse (String str, ParsePosition pos)
|
||||
{
|
||||
// Our strategy is simple: copy the text into a buffer,
|
||||
// translating or omitting locale-specific information. Then
|
||||
// let Double or Long convert the number for us.
|
||||
|
||||
boolean is_neg = false;
|
||||
int index = pos.getIndex();
|
||||
StringBuffer buf = new StringBuffer ();
|
||||
|
||||
// We have to check both prefixes, because one might be empty.
|
||||
// We want to pick the longest prefix that matches.
|
||||
boolean got_pos = str.startsWith(positivePrefix, index);
|
||||
String np = (negativePrefix != null
|
||||
? negativePrefix
|
||||
: positivePrefix + symbols.getMinusSign());
|
||||
boolean got_neg = str.startsWith(np, index);
|
||||
|
||||
if (got_pos && got_neg)
|
||||
{
|
||||
// By checking this way, we preserve ambiguity in the case
|
||||
// where the negative format differs only in suffix. We
|
||||
// check this again later.
|
||||
if (np.length() > positivePrefix.length())
|
||||
{
|
||||
is_neg = true;
|
||||
index += np.length();
|
||||
}
|
||||
else
|
||||
index += positivePrefix.length();
|
||||
}
|
||||
else if (got_neg)
|
||||
{
|
||||
is_neg = true;
|
||||
index += np.length();
|
||||
}
|
||||
else if (got_pos)
|
||||
index += positivePrefix.length();
|
||||
else
|
||||
{
|
||||
pos.setErrorIndex (index);
|
||||
return null;
|
||||
}
|
||||
|
||||
// FIXME: handle Inf and NaN.
|
||||
|
||||
// FIXME: do we have to respect minimum/maxmimum digit stuff?
|
||||
// What about leading zeros? What about multiplier?
|
||||
|
||||
int start_index = index;
|
||||
int max = str.length();
|
||||
char zero = symbols.getZeroDigit();
|
||||
int last_group = -1;
|
||||
boolean int_part = true;
|
||||
boolean exp_part = false;
|
||||
for (; index < max; ++index)
|
||||
{
|
||||
char c = str.charAt(index);
|
||||
|
||||
// FIXME: what about grouping size?
|
||||
if (groupingUsed && c == symbols.getGroupingSeparator())
|
||||
{
|
||||
if (last_group != -1
|
||||
&& (index - last_group) % groupingSize != 0)
|
||||
{
|
||||
pos.setErrorIndex(index);
|
||||
return null;
|
||||
}
|
||||
last_group = index;
|
||||
}
|
||||
else if (c >= zero && c <= zero + 9)
|
||||
{
|
||||
buf.append((char) (c - zero + '0'));
|
||||
exp_part = false;
|
||||
}
|
||||
else if (parseIntegerOnly)
|
||||
break;
|
||||
else if (c == symbols.getDecimalSeparator())
|
||||
{
|
||||
if (last_group != -1
|
||||
&& (index - last_group) % groupingSize != 0)
|
||||
{
|
||||
pos.setErrorIndex(index);
|
||||
return null;
|
||||
}
|
||||
buf.append('.');
|
||||
int_part = false;
|
||||
}
|
||||
else if (c == symbols.getExponential())
|
||||
{
|
||||
buf.append('E');
|
||||
int_part = false;
|
||||
exp_part = true;
|
||||
}
|
||||
else if (exp_part
|
||||
&& (c == '+' || c == '-' || c == symbols.getMinusSign()))
|
||||
{
|
||||
// For exponential notation.
|
||||
buf.append(c);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (index == start_index)
|
||||
{
|
||||
// Didn't see any digits.
|
||||
pos.setErrorIndex(index);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check the suffix. We must do this before converting the
|
||||
// buffer to a number to handle the case of a number which is
|
||||
// the most negative Long.
|
||||
boolean got_pos_suf = str.startsWith(positiveSuffix, index);
|
||||
String ns = (negativePrefix == null ? positiveSuffix : negativeSuffix);
|
||||
boolean got_neg_suf = str.startsWith(ns, index);
|
||||
if (is_neg)
|
||||
{
|
||||
if (! got_neg_suf)
|
||||
{
|
||||
pos.setErrorIndex(index);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else if (got_pos && got_neg && got_neg_suf)
|
||||
{
|
||||
is_neg = true;
|
||||
}
|
||||
else if (got_pos != got_pos_suf && got_neg != got_neg_suf)
|
||||
{
|
||||
pos.setErrorIndex(index);
|
||||
return null;
|
||||
}
|
||||
|
||||
String suffix = is_neg ? ns : positiveSuffix;
|
||||
if (is_neg)
|
||||
buf.insert(0, '-');
|
||||
|
||||
String t = buf.toString();
|
||||
Number result = null;
|
||||
try
|
||||
{
|
||||
result = new Long (t);
|
||||
}
|
||||
catch (NumberFormatException x1)
|
||||
{
|
||||
try
|
||||
{
|
||||
result = new Double (t);
|
||||
}
|
||||
catch (NumberFormatException x2)
|
||||
{
|
||||
}
|
||||
}
|
||||
if (result == null)
|
||||
{
|
||||
pos.setErrorIndex(index);
|
||||
return null;
|
||||
}
|
||||
|
||||
pos.setIndex(index + suffix.length());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setDecimalFormatSymbols (DecimalFormatSymbols newSymbols)
|
||||
{
|
||||
symbols = newSymbols;
|
||||
}
|
||||
|
||||
public void setDecimalSeparatorAlwaysShown (boolean newValue)
|
||||
{
|
||||
decimalSeparatorAlwaysShown = newValue;
|
||||
}
|
||||
|
||||
public void setGroupingSize (int groupSize)
|
||||
{
|
||||
groupingSize = (byte) groupSize;
|
||||
}
|
||||
|
||||
public void setMaximumFractionDigits (int newValue)
|
||||
{
|
||||
maximumFractionDigits = Math.min(newValue, 340);
|
||||
}
|
||||
|
||||
public void setMaximumIntegerDigits (int newValue)
|
||||
{
|
||||
maximumIntegerDigits = Math.min(newValue, 309);
|
||||
}
|
||||
|
||||
public void setMinimumFractionDigits (int newValue)
|
||||
{
|
||||
minimumFractionDigits = Math.min(newValue, 340);
|
||||
}
|
||||
|
||||
public void setMinimumIntegerDigits (int newValue)
|
||||
{
|
||||
minimumIntegerDigits = Math.min(newValue, 309);
|
||||
}
|
||||
|
||||
public void setMultiplier (int newValue)
|
||||
{
|
||||
multiplier = newValue;
|
||||
}
|
||||
|
||||
public void setNegativePrefix (String newValue)
|
||||
{
|
||||
negativePrefix = newValue;
|
||||
}
|
||||
|
||||
public void setNegativeSuffix (String newValue)
|
||||
{
|
||||
negativeSuffix = newValue;
|
||||
}
|
||||
|
||||
public void setPositivePrefix (String newValue)
|
||||
{
|
||||
positivePrefix = newValue;
|
||||
}
|
||||
|
||||
public void setPositiveSuffix (String newValue)
|
||||
{
|
||||
positiveSuffix = newValue;
|
||||
}
|
||||
|
||||
private final void quoteFix (StringBuffer buf, String text, String patChars)
|
||||
{
|
||||
int len = text.length();
|
||||
for (int index = 0; index < len; ++index)
|
||||
{
|
||||
char c = text.charAt(index);
|
||||
if (patChars.indexOf(c) != -1)
|
||||
{
|
||||
buf.append('\'');
|
||||
buf.append(c);
|
||||
buf.append('\'');
|
||||
}
|
||||
else
|
||||
buf.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
private final String computePattern (DecimalFormatSymbols syms)
|
||||
{
|
||||
StringBuffer mainPattern = new StringBuffer ();
|
||||
// We have to at least emit a zero for the minimum number of
|
||||
// digits. Past that we need hash marks up to the grouping
|
||||
// separator (and one beyond).
|
||||
int total_digits = Math.max(minimumIntegerDigits,
|
||||
groupingUsed ? groupingSize + 1: 0);
|
||||
for (int i = 0; i < total_digits - minimumIntegerDigits; ++i)
|
||||
mainPattern.append(syms.getDigit());
|
||||
for (int i = total_digits - minimumIntegerDigits; i < total_digits; ++i)
|
||||
mainPattern.append(syms.getZeroDigit());
|
||||
// Inserting the gropuing operator afterwards is easier.
|
||||
if (groupingUsed)
|
||||
mainPattern.insert(mainPattern.length() - groupingSize,
|
||||
syms.getGroupingSeparator());
|
||||
// See if we need decimal info.
|
||||
if (minimumFractionDigits > 0 || maximumFractionDigits > 0
|
||||
|| decimalSeparatorAlwaysShown)
|
||||
mainPattern.append(syms.getDecimalSeparator());
|
||||
for (int i = 0; i < minimumFractionDigits; ++i)
|
||||
mainPattern.append(syms.getZeroDigit());
|
||||
for (int i = minimumFractionDigits; i < maximumFractionDigits; ++i)
|
||||
mainPattern.append(syms.getDigit());
|
||||
if (useExponentialNotation)
|
||||
{
|
||||
mainPattern.append(syms.getExponential());
|
||||
for (int i = 0; i < minExponentDigits; ++i)
|
||||
mainPattern.append(syms.getZeroDigit());
|
||||
if (minExponentDigits == 0)
|
||||
mainPattern.append(syms.getDigit());
|
||||
}
|
||||
|
||||
String main = mainPattern.toString();
|
||||
String patChars = patternChars (syms);
|
||||
mainPattern.setLength(0);
|
||||
|
||||
quoteFix (mainPattern, positivePrefix, patChars);
|
||||
mainPattern.append(main);
|
||||
quoteFix (mainPattern, positiveSuffix, patChars);
|
||||
|
||||
if (negativePrefix != null)
|
||||
{
|
||||
quoteFix (mainPattern, negativePrefix, patChars);
|
||||
mainPattern.append(main);
|
||||
quoteFix (mainPattern, negativeSuffix, patChars);
|
||||
}
|
||||
|
||||
return mainPattern.toString();
|
||||
}
|
||||
|
||||
public String toLocalizedPattern ()
|
||||
{
|
||||
return computePattern (symbols);
|
||||
}
|
||||
|
||||
public String toPattern ()
|
||||
{
|
||||
return computePattern (nonLocalizedSymbols);
|
||||
}
|
||||
|
||||
// These names are fixed by the serialization spec.
|
||||
private boolean decimalSeparatorAlwaysShown;
|
||||
private byte groupingSize;
|
||||
private byte minExponentDigits;
|
||||
private int multiplier;
|
||||
private String negativePrefix;
|
||||
private String negativeSuffix;
|
||||
private String positivePrefix;
|
||||
private String positiveSuffix;
|
||||
private DecimalFormatSymbols symbols;
|
||||
private boolean useExponentialNotation;
|
||||
|
||||
// The locale-independent pattern symbols happen to be the same as
|
||||
// the US symbols.
|
||||
private static final DecimalFormatSymbols nonLocalizedSymbols
|
||||
= new DecimalFormatSymbols (Locale.US);
|
||||
}
|
293
libjava/java/text/DecimalFormatSymbols.java
Normal file
293
libjava/java/text/DecimalFormatSymbols.java
Normal file
|
@ -0,0 +1,293 @@
|
|||
// DecimalFormatSymbols.java - Symbols used to format numbers.
|
||||
|
||||
/* Copyright (C) 1999 Cygnus Solutions
|
||||
|
||||
This file is part of libgcj.
|
||||
|
||||
This software is copyrighted work licensed under the terms of the
|
||||
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
||||
details. */
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Locale;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* @author Tom Tromey <tromey@cygnus.com>
|
||||
* @date February 24, 1999
|
||||
*/
|
||||
/* Written using "Java Class Libraries", 2nd edition, plus online
|
||||
* API docs for JDK 1.2 from http://www.javasoft.com.
|
||||
* Status: Believed complete and correct to 1.2, except serialization.
|
||||
*/
|
||||
|
||||
public final class DecimalFormatSymbols implements Cloneable, Serializable
|
||||
{
|
||||
public Object clone ()
|
||||
{
|
||||
return new DecimalFormatSymbols (this);
|
||||
}
|
||||
|
||||
private DecimalFormatSymbols (DecimalFormatSymbols orig)
|
||||
{
|
||||
this.currencySymbol = orig.currencySymbol;
|
||||
this.decimalSeparator = orig.decimalSeparator;
|
||||
this.digit = orig.digit;
|
||||
this.exponential = orig.exponential;
|
||||
this.groupingSeparator = orig.groupingSeparator;
|
||||
this.infinity = orig.infinity;
|
||||
this.intlCurrencySymbol = orig.intlCurrencySymbol;
|
||||
this.minusSign = orig.minusSign;
|
||||
this.NaN = orig.NaN;
|
||||
this.patternSeparator = orig.patternSeparator;
|
||||
this.percent = orig.percent;
|
||||
this.perMill = orig.perMill;
|
||||
this.zeroDigit = orig.zeroDigit;
|
||||
}
|
||||
|
||||
public DecimalFormatSymbols ()
|
||||
{
|
||||
this (Locale.getDefault());
|
||||
}
|
||||
|
||||
private final String safeGetString (ResourceBundle bundle,
|
||||
String name, String def)
|
||||
{
|
||||
if (bundle != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return bundle.getString(name);
|
||||
}
|
||||
catch (MissingResourceException x)
|
||||
{
|
||||
}
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
public final char safeGetChar (ResourceBundle bundle,
|
||||
String name, char def)
|
||||
{
|
||||
String r = null;
|
||||
if (bundle != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
r = bundle.getString(name);
|
||||
}
|
||||
catch (MissingResourceException x)
|
||||
{
|
||||
}
|
||||
}
|
||||
if (r == null || r.length() < 1)
|
||||
return def;
|
||||
return r.charAt(0);
|
||||
}
|
||||
|
||||
public DecimalFormatSymbols (Locale loc)
|
||||
{
|
||||
ResourceBundle res;
|
||||
try
|
||||
{
|
||||
res = ResourceBundle.getBundle("gnu.gcj.text.LocaleData", loc);
|
||||
}
|
||||
catch (MissingResourceException x)
|
||||
{
|
||||
res = null;
|
||||
}
|
||||
currencySymbol = safeGetString (res, "currencySymbol", "$");
|
||||
decimalSeparator = safeGetChar (res, "decimalSeparator", '.');
|
||||
digit = safeGetChar (res, "digit", '#');
|
||||
exponential = safeGetChar (res, "exponential", 'E');
|
||||
groupingSeparator = safeGetChar (res, "groupingSeparator", ',');
|
||||
infinity = safeGetString (res, "infinity", "\u221e");
|
||||
// FIXME: default?
|
||||
intlCurrencySymbol = safeGetString (res, "intlCurrencySymbol", "$");
|
||||
minusSign = safeGetChar (res, "minusSign", '-');
|
||||
NaN = safeGetString (res, "NaN", "\ufffd");
|
||||
patternSeparator = safeGetChar (res, "patternSeparator", ';');
|
||||
percent = safeGetChar (res, "percent", '%');
|
||||
perMill = safeGetChar (res, "perMill", '\u2030');
|
||||
zeroDigit = safeGetChar (res, "zeroDigit", '0');
|
||||
}
|
||||
|
||||
public boolean equals (Object obj)
|
||||
{
|
||||
if (! (obj instanceof DecimalFormatSymbols))
|
||||
return false;
|
||||
DecimalFormatSymbols dfs = (DecimalFormatSymbols) obj;
|
||||
return (currencySymbol.equals(dfs.currencySymbol)
|
||||
&& decimalSeparator == dfs.decimalSeparator
|
||||
&& digit == dfs.digit
|
||||
&& exponential == dfs.exponential
|
||||
&& groupingSeparator == dfs.groupingSeparator
|
||||
&& infinity.equals(dfs.infinity)
|
||||
&& intlCurrencySymbol.equals(dfs.intlCurrencySymbol)
|
||||
&& minusSign == dfs.minusSign
|
||||
&& NaN.equals(dfs.NaN)
|
||||
&& patternSeparator == dfs.patternSeparator
|
||||
&& percent == dfs.percent
|
||||
&& perMill == dfs.perMill
|
||||
&& zeroDigit == dfs.zeroDigit);
|
||||
}
|
||||
|
||||
public String getCurrencySymbol ()
|
||||
{
|
||||
return currencySymbol;
|
||||
}
|
||||
|
||||
public char getDecimalSeparator ()
|
||||
{
|
||||
return decimalSeparator;
|
||||
}
|
||||
|
||||
public char getDigit ()
|
||||
{
|
||||
return digit;
|
||||
}
|
||||
|
||||
// This is our own extension.
|
||||
char getExponential ()
|
||||
{
|
||||
return exponential;
|
||||
}
|
||||
|
||||
public char getGroupingSeparator ()
|
||||
{
|
||||
return groupingSeparator;
|
||||
}
|
||||
|
||||
public String getInfinity ()
|
||||
{
|
||||
return infinity;
|
||||
}
|
||||
|
||||
public String getInternationalCurrencySymbol ()
|
||||
{
|
||||
return intlCurrencySymbol;
|
||||
}
|
||||
|
||||
public char getMinusSign ()
|
||||
{
|
||||
return minusSign;
|
||||
}
|
||||
|
||||
public String getNaN ()
|
||||
{
|
||||
return NaN;
|
||||
}
|
||||
|
||||
public char getPatternSeparator ()
|
||||
{
|
||||
return patternSeparator;
|
||||
}
|
||||
|
||||
public char getPercent ()
|
||||
{
|
||||
return percent;
|
||||
}
|
||||
|
||||
public char getPerMill ()
|
||||
{
|
||||
return perMill;
|
||||
}
|
||||
|
||||
public char getZeroDigit ()
|
||||
{
|
||||
return zeroDigit;
|
||||
}
|
||||
|
||||
public int hashCode ()
|
||||
{
|
||||
// Compute based on zero digit, grouping separator, and decimal
|
||||
// separator -- JCL book. This probably isn't a very good hash
|
||||
// code.
|
||||
return zeroDigit << 16 + groupingSeparator << 8 + decimalSeparator;
|
||||
}
|
||||
|
||||
public void setCurrenySymbol (String currency)
|
||||
{
|
||||
currencySymbol = currency;
|
||||
}
|
||||
|
||||
public void setDecimalSeparator (char decimalSep)
|
||||
{
|
||||
decimalSeparator = decimalSep;
|
||||
}
|
||||
|
||||
public void setDigit (char digit)
|
||||
{
|
||||
this.digit = digit;
|
||||
}
|
||||
|
||||
// This is our own extension.
|
||||
void setExponential (char exp)
|
||||
{
|
||||
exponential = exp;
|
||||
}
|
||||
|
||||
public void setGroupingSeparator (char groupSep)
|
||||
{
|
||||
groupingSeparator = groupSep;
|
||||
}
|
||||
|
||||
public void setInfinity (String infinity)
|
||||
{
|
||||
this.infinity = infinity;
|
||||
}
|
||||
|
||||
public void setInternationalCurrencySymbol (String currency)
|
||||
{
|
||||
intlCurrencySymbol = currency;
|
||||
}
|
||||
|
||||
public void setMinusSign (char minusSign)
|
||||
{
|
||||
this.minusSign = minusSign;
|
||||
}
|
||||
|
||||
public void setNaN (String nan)
|
||||
{
|
||||
NaN = nan;
|
||||
}
|
||||
|
||||
public void setPatternSeparator (char patternSep)
|
||||
{
|
||||
patternSeparator = patternSep;
|
||||
}
|
||||
|
||||
public void setPercent (char percent)
|
||||
{
|
||||
this.percent = percent;
|
||||
}
|
||||
|
||||
public void setPerMill (char perMill)
|
||||
{
|
||||
this.perMill = perMill;
|
||||
}
|
||||
|
||||
public void setZeroDigit (char zeroDigit)
|
||||
{
|
||||
this.zeroDigit = zeroDigit;
|
||||
}
|
||||
|
||||
// The names of the instance variables are fixed by the
|
||||
// serialization spec.
|
||||
private String currencySymbol;
|
||||
private char decimalSeparator;
|
||||
private char digit;
|
||||
private char exponential;
|
||||
private char groupingSeparator;
|
||||
private String infinity;
|
||||
private String intlCurrencySymbol;
|
||||
private char minusSign;
|
||||
private String NaN;
|
||||
private char patternSeparator;
|
||||
private char percent;
|
||||
private char perMill;
|
||||
private char zeroDigit;
|
||||
}
|
65
libjava/java/text/FieldPosition.java
Normal file
65
libjava/java/text/FieldPosition.java
Normal file
|
@ -0,0 +1,65 @@
|
|||
/* Copyright (C) 1998, 1999 Cygnus Solutions
|
||||
|
||||
This file is part of libgcj.
|
||||
|
||||
This software is copyrighted work licensed under the terms of the
|
||||
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
||||
details. */
|
||||
|
||||
package java.text;
|
||||
|
||||
/**
|
||||
* @author Per Bothner <bothner@cygnus.com>
|
||||
* @date October 25, 1998.
|
||||
*/
|
||||
/* Written using "Java Class Libraries", 2nd edition, plus online
|
||||
* API docs for JDK 1.2 beta from http://www.javasoft.com.
|
||||
* Status: Believed complete and correct.
|
||||
* Includes JDK 1.2 methods.
|
||||
*/
|
||||
|
||||
public class FieldPosition
|
||||
{
|
||||
int field;
|
||||
int beginIndex;
|
||||
int endIndex;
|
||||
|
||||
public FieldPosition (int field)
|
||||
{
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
public int getField ()
|
||||
{
|
||||
return field;
|
||||
}
|
||||
|
||||
public int getBeginIndex ()
|
||||
{
|
||||
return beginIndex;
|
||||
}
|
||||
|
||||
public int getEndIndex ()
|
||||
{
|
||||
return endIndex;
|
||||
}
|
||||
|
||||
public void setBeginIndex (int index)
|
||||
{
|
||||
beginIndex = index;
|
||||
}
|
||||
|
||||
public void setEndIndex (int index)
|
||||
{
|
||||
endIndex = index;
|
||||
}
|
||||
|
||||
public boolean equals (Object obj)
|
||||
{
|
||||
if (! (obj instanceof FieldPosition))
|
||||
return false;
|
||||
FieldPosition other = (FieldPosition) obj;
|
||||
return (field == other.field
|
||||
&& beginIndex == other.beginIndex && endIndex == other.endIndex);
|
||||
}
|
||||
}
|
51
libjava/java/text/Format.java
Normal file
51
libjava/java/text/Format.java
Normal file
|
@ -0,0 +1,51 @@
|
|||
/* Copyright (C) 1998, 1999 Cygnus Solutions
|
||||
|
||||
This file is part of libgcj.
|
||||
|
||||
This software is copyrighted work licensed under the terms of the
|
||||
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
||||
details. */
|
||||
|
||||
package java.text;
|
||||
|
||||
/**
|
||||
* @author Per Bothner <bothner@cygnus.com>
|
||||
* @date October 25, 1998.
|
||||
*/
|
||||
/* Written using "Java Class Libraries", 2nd edition, plus online
|
||||
* API docs for JDK 1.2 beta from http://www.javasoft.com.
|
||||
* Status: Believed complete and correct.
|
||||
*/
|
||||
|
||||
public abstract class Format implements java.io.Serializable, Cloneable
|
||||
{
|
||||
public Format ()
|
||||
{
|
||||
}
|
||||
|
||||
public abstract StringBuffer format (Object obj,
|
||||
StringBuffer sbuf, FieldPosition pos);
|
||||
|
||||
public final String format (Object obj)
|
||||
{
|
||||
StringBuffer sbuf = new StringBuffer();
|
||||
format(obj, sbuf, new FieldPosition(0));
|
||||
return sbuf.toString();
|
||||
}
|
||||
|
||||
public abstract Object parseObject (String source, ParsePosition pos);
|
||||
|
||||
public Object parseObject (String source) throws ParseException
|
||||
{
|
||||
ParsePosition pos = new ParsePosition(0);
|
||||
Object result = parseObject (source, pos);
|
||||
if (result == null)
|
||||
{
|
||||
int index = pos.getErrorIndex();
|
||||
if (index < 0)
|
||||
index = pos.getIndex();
|
||||
throw new ParseException("parseObject failed", index);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
543
libjava/java/text/MessageFormat.java
Normal file
543
libjava/java/text/MessageFormat.java
Normal file
|
@ -0,0 +1,543 @@
|
|||
// MessageFormat.java - Localized message formatting.
|
||||
|
||||
/* Copyright (C) 1999 Cygnus Solutions
|
||||
|
||||
This file is part of libgcj.
|
||||
|
||||
This software is copyrighted work licensed under the terms of the
|
||||
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
||||
details. */
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* @author Tom Tromey <tromey@cygnus.com>
|
||||
* @date March 3, 1999
|
||||
*/
|
||||
/* Written using "Java Class Libraries", 2nd edition, plus online
|
||||
* API docs for JDK 1.2 from http://www.javasoft.com.
|
||||
* Status: Believed complete and correct to 1.2, except serialization.
|
||||
* and parsing.
|
||||
*/
|
||||
|
||||
final class MessageFormatElement
|
||||
{
|
||||
// Argument number.
|
||||
int argNumber;
|
||||
// Formatter to be used. This is the format set by setFormat.
|
||||
Format setFormat;
|
||||
// Formatter to be used based on the type.
|
||||
Format format;
|
||||
|
||||
// Argument will be checked to make sure it is an instance of this
|
||||
// class.
|
||||
Class formatClass;
|
||||
|
||||
// Formatter type.
|
||||
String type;
|
||||
// Formatter style.
|
||||
String style;
|
||||
|
||||
// Text to follow this element.
|
||||
String trailer;
|
||||
|
||||
// FIXME: shouldn't need this.
|
||||
Class forName (String name)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Class.forName (name);
|
||||
}
|
||||
catch (ClassNotFoundException x)
|
||||
{
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Recompute the locale-based formatter.
|
||||
void setLocale (Locale loc)
|
||||
{
|
||||
if (type == null)
|
||||
;
|
||||
else if (type.equals("number"))
|
||||
{
|
||||
// FIXME: named class literal.
|
||||
// formatClass = Number.class;
|
||||
formatClass = forName ("java.lang.Number");
|
||||
|
||||
if (style == null)
|
||||
format = NumberFormat.getInstance(loc);
|
||||
else if (style.equals("currency"))
|
||||
format = NumberFormat.getCurrencyInstance(loc);
|
||||
else if (style.equals("percent"))
|
||||
format = NumberFormat.getPercentInstance(loc);
|
||||
else if (style.equals("integer"))
|
||||
{
|
||||
NumberFormat nf = NumberFormat.getNumberInstance(loc);
|
||||
nf.setMaximumFractionDigits(0);
|
||||
nf.setGroupingUsed(false);
|
||||
format = nf;
|
||||
}
|
||||
else
|
||||
{
|
||||
format = NumberFormat.getNumberInstance(loc);
|
||||
DecimalFormat df = (DecimalFormat) format;
|
||||
try
|
||||
{
|
||||
df.applyPattern(style);
|
||||
}
|
||||
catch (ParseException x)
|
||||
{
|
||||
throw new IllegalArgumentException (x.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type.equals("time") || type.equals("date"))
|
||||
{
|
||||
// FIXME: named class literal.
|
||||
// formatClass = Date.class;
|
||||
formatClass = forName ("java.util.Date");
|
||||
|
||||
int val = DateFormat.DEFAULT;
|
||||
if (style == null)
|
||||
;
|
||||
if (style.equals("short"))
|
||||
val = DateFormat.SHORT;
|
||||
else if (style.equals("medium"))
|
||||
val = DateFormat.MEDIUM;
|
||||
else if (style.equals("long"))
|
||||
val = DateFormat.LONG;
|
||||
else if (style.equals("full"))
|
||||
val = DateFormat.FULL;
|
||||
|
||||
if (type.equals("time"))
|
||||
format = DateFormat.getTimeInstance(val, loc);
|
||||
else
|
||||
format = DateFormat.getDateInstance(val, loc);
|
||||
|
||||
if (style != null && val == DateFormat.DEFAULT)
|
||||
{
|
||||
SimpleDateFormat sdf = (SimpleDateFormat) format;
|
||||
sdf.applyPattern(style);
|
||||
}
|
||||
}
|
||||
else if (type.equals("choice"))
|
||||
{
|
||||
// FIXME: named class literal.
|
||||
// formatClass = Number.class;
|
||||
formatClass = forName ("java.lang.Number");
|
||||
|
||||
if (style == null)
|
||||
throw new
|
||||
IllegalArgumentException ("style required for choice format");
|
||||
format = new ChoiceFormat (style);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class MessageFormat extends Format
|
||||
{
|
||||
// Helper that returns the text up to the next format opener. The
|
||||
// text is put into BUFFER. Returns index of character after end of
|
||||
// string. Throws IllegalArgumentException on error.
|
||||
private static final int scanString (String pat, int index,
|
||||
StringBuffer buffer)
|
||||
{
|
||||
int max = pat.length();
|
||||
buffer.setLength(0);
|
||||
for (; index < max; ++index)
|
||||
{
|
||||
char c = pat.charAt(index);
|
||||
if (c == '\'' && index + 2 < max && pat.charAt(index + 2) == '\'')
|
||||
{
|
||||
buffer.append(pat.charAt(index + 1));
|
||||
index += 2;
|
||||
}
|
||||
else if (c == '\'' && index + 1 < max
|
||||
&& pat.charAt(index + 1) == '\'')
|
||||
{
|
||||
buffer.append(c);
|
||||
++index;
|
||||
}
|
||||
else if (c == '{')
|
||||
break;
|
||||
else if (c == '}')
|
||||
throw new IllegalArgumentException ();
|
||||
else
|
||||
buffer.append(c);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
// This helper retrieves a single part of a format element. Returns
|
||||
// the index of the terminating character.
|
||||
private static final int scanFormatElement (String pat, int index,
|
||||
StringBuffer buffer,
|
||||
char term)
|
||||
{
|
||||
int max = pat.length();
|
||||
buffer.setLength(0);
|
||||
int brace_depth = 1;
|
||||
|
||||
for (; index < max; ++index)
|
||||
{
|
||||
char c = pat.charAt(index);
|
||||
if (c == '\'' && index + 2 < max && pat.charAt(index + 2) == '\'')
|
||||
{
|
||||
buffer.append(c);
|
||||
buffer.append(pat.charAt(index + 1));
|
||||
buffer.append(c);
|
||||
index += 2;
|
||||
}
|
||||
else if (c == '\'' && index + 1 < max
|
||||
&& pat.charAt(index + 1) == '\'')
|
||||
{
|
||||
buffer.append(c);
|
||||
++index;
|
||||
}
|
||||
else if (c == '{')
|
||||
{
|
||||
buffer.append(c);
|
||||
++brace_depth;
|
||||
}
|
||||
else if (c == '}')
|
||||
{
|
||||
if (--brace_depth == 0)
|
||||
break;
|
||||
buffer.append(c);
|
||||
}
|
||||
// Check for TERM after braces, because TERM might be `}'.
|
||||
else if (c == term)
|
||||
break;
|
||||
else
|
||||
buffer.append(c);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
// This is used to parse a format element and whatever non-format
|
||||
// text might trail it.
|
||||
private static final int scanFormat (String pat, int index,
|
||||
StringBuffer buffer, Vector elts,
|
||||
Locale locale)
|
||||
{
|
||||
MessageFormatElement mfe = new MessageFormatElement ();
|
||||
elts.addElement(mfe);
|
||||
|
||||
int max = pat.length();
|
||||
|
||||
// Skip the opening `{'.
|
||||
++index;
|
||||
|
||||
// Fetch the argument number.
|
||||
index = scanFormatElement (pat, index, buffer, ',');
|
||||
try
|
||||
{
|
||||
mfe.argNumber = Integer.parseInt(buffer.toString());
|
||||
}
|
||||
catch (NumberFormatException nfx)
|
||||
{
|
||||
throw new IllegalArgumentException ();
|
||||
}
|
||||
|
||||
// Extract the element format.
|
||||
if (index < max && pat.charAt(index) == ',')
|
||||
{
|
||||
index = scanFormatElement (pat, index + 1, buffer, ',');
|
||||
mfe.type = buffer.toString();
|
||||
|
||||
// Extract the style.
|
||||
if (index < max && pat.charAt(index) == ',')
|
||||
{
|
||||
index = scanFormatElement (pat, index + 1, buffer, '}');
|
||||
mfe.style = buffer.toString ();
|
||||
}
|
||||
}
|
||||
|
||||
// Advance past the last terminator.
|
||||
if (index >= max || pat.charAt(index) != '}')
|
||||
throw new IllegalArgumentException ();
|
||||
++index;
|
||||
|
||||
// Now fetch trailing string.
|
||||
index = scanString (pat, index, buffer);
|
||||
mfe.trailer = buffer.toString ();
|
||||
|
||||
mfe.setLocale(locale);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
public void applyPattern (String newPattern)
|
||||
{
|
||||
pattern = newPattern;
|
||||
|
||||
StringBuffer tempBuffer = new StringBuffer ();
|
||||
|
||||
int index = scanString (newPattern, 0, tempBuffer);
|
||||
leader = tempBuffer.toString();
|
||||
|
||||
Vector elts = new Vector ();
|
||||
while (index < newPattern.length())
|
||||
index = scanFormat (newPattern, index, tempBuffer, elts, locale);
|
||||
|
||||
elements = new MessageFormatElement[elts.size()];
|
||||
elts.copyInto(elements);
|
||||
}
|
||||
|
||||
public Object clone ()
|
||||
{
|
||||
MessageFormat c = new MessageFormat ();
|
||||
c.setLocale(locale);
|
||||
c.applyPattern(pattern);
|
||||
return (Object) c;
|
||||
}
|
||||
|
||||
public boolean equals (Object obj)
|
||||
{
|
||||
if (! (obj instanceof MessageFormat))
|
||||
return false;
|
||||
MessageFormat mf = (MessageFormat) obj;
|
||||
return (pattern.equals(mf.pattern)
|
||||
&& locale.equals(mf.locale));
|
||||
}
|
||||
|
||||
public static String format (String pattern, Object arguments[])
|
||||
{
|
||||
MessageFormat mf = new MessageFormat (pattern);
|
||||
StringBuffer sb = new StringBuffer ();
|
||||
FieldPosition fp = new FieldPosition (NumberFormat.INTEGER_FIELD);
|
||||
return mf.format(arguments, sb, fp).toString();
|
||||
}
|
||||
|
||||
public final StringBuffer format (Object arguments[], StringBuffer appendBuf,
|
||||
FieldPosition ignore)
|
||||
{
|
||||
appendBuf.append(leader);
|
||||
|
||||
for (int i = 0; i < elements.length; ++i)
|
||||
{
|
||||
if (elements[i].argNumber >= arguments.length)
|
||||
throw new IllegalArgumentException ();
|
||||
Object thisArg = arguments[elements[i].argNumber];
|
||||
|
||||
Format formatter = null;
|
||||
if (elements[i].setFormat != null)
|
||||
formatter = elements[i].setFormat;
|
||||
else if (elements[i].format != null)
|
||||
{
|
||||
if (elements[i].formatClass != null
|
||||
&& ! elements[i].formatClass.isInstance(thisArg))
|
||||
throw new IllegalArgumentException ();
|
||||
formatter = elements[i].format;
|
||||
}
|
||||
else if (thisArg instanceof Number)
|
||||
formatter = NumberFormat.getInstance(locale);
|
||||
else if (thisArg instanceof Date)
|
||||
formatter = DateFormat.getTimeInstance(DateFormat.DEFAULT, locale);
|
||||
else
|
||||
appendBuf.append(thisArg);
|
||||
|
||||
if (formatter != null)
|
||||
{
|
||||
// Special-case ChoiceFormat.
|
||||
if (formatter instanceof ChoiceFormat)
|
||||
{
|
||||
StringBuffer buf = new StringBuffer ();
|
||||
// FIXME: don't actually know what is correct here.
|
||||
// Can a sub-format refer to any argument, or just
|
||||
// the single argument passed to it? Must test
|
||||
// against JDK.
|
||||
formatter.format(thisArg, buf, ignore);
|
||||
MessageFormat mf = new MessageFormat ();
|
||||
mf.setLocale(locale);
|
||||
mf.applyPattern(buf.toString());
|
||||
formatter = mf;
|
||||
}
|
||||
formatter.format(thisArg, appendBuf, ignore);
|
||||
}
|
||||
|
||||
appendBuf.append(elements[i].trailer);
|
||||
}
|
||||
|
||||
return appendBuf;
|
||||
}
|
||||
|
||||
public final StringBuffer format (Object singleArg, StringBuffer appendBuf,
|
||||
FieldPosition ignore)
|
||||
{
|
||||
Object[] args = new Object[1];
|
||||
args[0] = singleArg;
|
||||
return format (args, appendBuf, ignore);
|
||||
}
|
||||
|
||||
public Format[] getFormats ()
|
||||
{
|
||||
Format[] f = new Format[elements.length];
|
||||
for (int i = elements.length - 1; i >= 0; --i)
|
||||
f[i] = elements[i].setFormat;
|
||||
return f;
|
||||
}
|
||||
|
||||
public Locale getLocale ()
|
||||
{
|
||||
return locale;
|
||||
}
|
||||
|
||||
public int hashCode ()
|
||||
{
|
||||
// FIXME: not a very good hash.
|
||||
return pattern.hashCode() + locale.hashCode();
|
||||
}
|
||||
|
||||
private MessageFormat ()
|
||||
{
|
||||
}
|
||||
|
||||
public MessageFormat (String pattern)
|
||||
{
|
||||
applyPattern (pattern);
|
||||
}
|
||||
|
||||
public Object[] parse (String sourceStr, ParsePosition pos)
|
||||
{
|
||||
// Check initial text.
|
||||
int index = pos.getIndex();
|
||||
if (! sourceStr.startsWith(leader, index))
|
||||
{
|
||||
pos.setErrorIndex(index);
|
||||
return null;
|
||||
}
|
||||
index += leader.length();
|
||||
|
||||
Vector results = new Vector (elements.length, 1);
|
||||
// Now check each format.
|
||||
for (int i = 0; i < elements.length; ++i)
|
||||
{
|
||||
Format formatter = null;
|
||||
if (elements[i].setFormat != null)
|
||||
formatter = elements[i].setFormat;
|
||||
else if (elements[i].format != null)
|
||||
formatter = elements[i].format;
|
||||
|
||||
Object value = null;
|
||||
if (formatter instanceof ChoiceFormat)
|
||||
{
|
||||
// We must special-case a ChoiceFormat because it might
|
||||
// have recursive formatting.
|
||||
ChoiceFormat cf = (ChoiceFormat) formatter;
|
||||
String[] formats = (String[]) cf.getFormats();
|
||||
double[] limits = (double[]) cf.getLimits();
|
||||
MessageFormat subfmt = new MessageFormat ();
|
||||
subfmt.setLocale(locale);
|
||||
ParsePosition subpos = new ParsePosition (index);
|
||||
|
||||
int j;
|
||||
for (j = 0; value == null && j < limits.length; ++j)
|
||||
{
|
||||
subfmt.applyPattern(formats[j]);
|
||||
subpos.setIndex(index);
|
||||
value = subfmt.parse(sourceStr, subpos);
|
||||
}
|
||||
if (value != null)
|
||||
{
|
||||
index = subpos.getIndex();
|
||||
value = new Double (limits[j]);
|
||||
}
|
||||
}
|
||||
else if (formatter != null)
|
||||
{
|
||||
pos.setIndex(index);
|
||||
value = formatter.parseObject(sourceStr, pos);
|
||||
if (value != null)
|
||||
index = pos.getIndex();
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have a String format. This can lose in a number
|
||||
// of ways, but we give it a shot.
|
||||
int next_index = sourceStr.indexOf(elements[i].trailer, index);
|
||||
if (next_index == -1)
|
||||
{
|
||||
pos.setErrorIndex(index);
|
||||
return null;
|
||||
}
|
||||
value = sourceStr.substring(index, next_index);
|
||||
index = next_index;
|
||||
}
|
||||
|
||||
if (value == null
|
||||
|| ! sourceStr.startsWith(elements[i].trailer, index))
|
||||
{
|
||||
pos.setErrorIndex(index);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (elements[i].argNumber >= results.size())
|
||||
results.setSize(elements[i].argNumber + 1);
|
||||
results.setElementAt(value, elements[i].argNumber);
|
||||
|
||||
index += elements[i].trailer.length();
|
||||
}
|
||||
|
||||
Object[] r = new Object[results.size()];
|
||||
results.copyInto(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
public Object[] parse (String sourceStr) throws ParseException
|
||||
{
|
||||
ParsePosition pp = new ParsePosition (0);
|
||||
Object[] r = parse (sourceStr, pp);
|
||||
if (r == null)
|
||||
throw new ParseException ("couldn't parse string", pp.getErrorIndex());
|
||||
return r;
|
||||
}
|
||||
|
||||
public Object parseObject (String sourceStr, ParsePosition pos)
|
||||
{
|
||||
return parse (sourceStr, pos);
|
||||
}
|
||||
|
||||
public void setFormat (int variableNum, Format newFormat)
|
||||
{
|
||||
elements[variableNum].setFormat = newFormat;
|
||||
}
|
||||
|
||||
public void setFormats (Format[] newFormats)
|
||||
{
|
||||
if (newFormats.length < elements.length)
|
||||
throw new IllegalArgumentException ();
|
||||
int len = Math.min(newFormats.length, elements.length);
|
||||
for (int i = 0; i < len; ++i)
|
||||
elements[i].setFormat = newFormats[i];
|
||||
}
|
||||
|
||||
public void setLocale (Locale loc)
|
||||
{
|
||||
locale = loc;
|
||||
if (elements != null)
|
||||
{
|
||||
for (int i = 0; i < elements.length; ++i)
|
||||
elements[i].setLocale(loc);
|
||||
}
|
||||
}
|
||||
|
||||
public String toPattern ()
|
||||
{
|
||||
return pattern;
|
||||
}
|
||||
|
||||
// The pattern string.
|
||||
private String pattern;
|
||||
// The locale.
|
||||
private Locale locale;
|
||||
// Variables.
|
||||
private MessageFormatElement[] elements;
|
||||
// Leader text.
|
||||
private String leader;
|
||||
}
|
236
libjava/java/text/NumberFormat.java
Normal file
236
libjava/java/text/NumberFormat.java
Normal file
|
@ -0,0 +1,236 @@
|
|||
/* Copyright (C) 1998, 1999 Cygnus Solutions
|
||||
|
||||
This file is part of libgcj.
|
||||
|
||||
This software is copyrighted work licensed under the terms of the
|
||||
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
||||
details. */
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.MissingResourceException;
|
||||
|
||||
/**
|
||||
* @author Tom Tromey <tromey@cygnus.com>
|
||||
* @date March 4, 1999
|
||||
*/
|
||||
/* Written using "Java Class Libraries", 2nd edition, plus online
|
||||
* API docs for JDK 1.2 from http://www.javasoft.com.
|
||||
* Status: Believed complete and correct to 1.2, except serialization
|
||||
* and getAvailableLocales.
|
||||
*/
|
||||
|
||||
public abstract class NumberFormat extends Format implements Cloneable
|
||||
{
|
||||
public static final int INTEGER_FIELD = 0;
|
||||
public static final int FRACTION_FIELD = 1;
|
||||
|
||||
public final String format (long number)
|
||||
{
|
||||
StringBuffer sbuf = new StringBuffer(50);
|
||||
format (number, sbuf, null);
|
||||
return sbuf.toString();
|
||||
}
|
||||
|
||||
public final StringBuffer format (Object obj, StringBuffer sbuf,
|
||||
FieldPosition pos)
|
||||
{
|
||||
return format(((Number) obj).doubleValue(), sbuf, pos);
|
||||
}
|
||||
|
||||
public abstract StringBuffer format (double number,
|
||||
StringBuffer sbuf, FieldPosition pos);
|
||||
|
||||
public abstract StringBuffer format (long number,
|
||||
StringBuffer sbuf, FieldPosition pos);
|
||||
|
||||
public static Locale[] getAvailableLocales ()
|
||||
{
|
||||
// FIXME.
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final NumberFormat computeInstance (Locale loc,
|
||||
String resource,
|
||||
String def)
|
||||
{
|
||||
ResourceBundle res;
|
||||
try
|
||||
{
|
||||
res = ResourceBundle.getBundle("gnu.gcj.text.LocaleData", loc);
|
||||
}
|
||||
catch (MissingResourceException x)
|
||||
{
|
||||
res = null;
|
||||
}
|
||||
String fmt;
|
||||
try
|
||||
{
|
||||
fmt = res == null ? def : res.getString(resource);
|
||||
}
|
||||
catch (MissingResourceException x)
|
||||
{
|
||||
fmt = def;
|
||||
}
|
||||
DecimalFormatSymbols dfs = new DecimalFormatSymbols (loc);
|
||||
return new DecimalFormat (fmt, dfs);
|
||||
}
|
||||
|
||||
public static final NumberFormat getCurrencyInstance ()
|
||||
{
|
||||
return getCurrencyInstance (Locale.getDefault());
|
||||
}
|
||||
|
||||
public static NumberFormat getCurrencyInstance (Locale loc)
|
||||
{
|
||||
return computeInstance (loc, "currencyFormat", "$#,##0.00;($#,##0.00)");
|
||||
}
|
||||
|
||||
public static final NumberFormat getInstance ()
|
||||
{
|
||||
return getInstance (Locale.getDefault());
|
||||
}
|
||||
|
||||
public static NumberFormat getInstance (Locale loc)
|
||||
{
|
||||
// For now always return a number instance.
|
||||
return getNumberInstance (loc);
|
||||
}
|
||||
|
||||
public int getMaximumFractionDigits ()
|
||||
{
|
||||
return maximumFractionDigits;
|
||||
}
|
||||
|
||||
public int getMaximumIntegerDigits ()
|
||||
{
|
||||
return maximumIntegerDigits;
|
||||
}
|
||||
|
||||
public int getMinimumFractionDigits ()
|
||||
{
|
||||
return minimumFractionDigits;
|
||||
}
|
||||
|
||||
public int getMinimumIntegerDigits ()
|
||||
{
|
||||
return minimumIntegerDigits;
|
||||
}
|
||||
|
||||
public static final NumberFormat getNumberInstance ()
|
||||
{
|
||||
return getNumberInstance (Locale.getDefault());
|
||||
}
|
||||
|
||||
public static NumberFormat getNumberInstance (Locale loc)
|
||||
{
|
||||
return computeInstance (loc, "numberFormat", "#,##0.###");
|
||||
}
|
||||
|
||||
public static final NumberFormat getPercentInstance ()
|
||||
{
|
||||
return getPercentInstance (Locale.getDefault());
|
||||
}
|
||||
|
||||
public static NumberFormat getPercentInstance (Locale loc)
|
||||
{
|
||||
return computeInstance (loc, "percentFormat", "#,##0%");
|
||||
}
|
||||
|
||||
public int hashCode ()
|
||||
{
|
||||
int hash = super.hashCode();
|
||||
hash ^= (maximumFractionDigits + maximumIntegerDigits
|
||||
+ minimumFractionDigits + minimumIntegerDigits);
|
||||
if (groupingUsed)
|
||||
hash ^= 0xf0f0;
|
||||
if (parseIntegerOnly)
|
||||
hash ^= 0x0f0f;
|
||||
return hash;
|
||||
}
|
||||
|
||||
public boolean isGroupingUsed ()
|
||||
{
|
||||
return groupingUsed;
|
||||
}
|
||||
|
||||
public boolean isParseIntegerOnly ()
|
||||
{
|
||||
return parseIntegerOnly;
|
||||
}
|
||||
|
||||
public NumberFormat ()
|
||||
{
|
||||
}
|
||||
|
||||
public abstract Number parse (String sourceStr, ParsePosition pos);
|
||||
|
||||
public Number parse (String sourceStr) throws ParseException
|
||||
{
|
||||
ParsePosition pp = new ParsePosition (0);
|
||||
Number r = parse (sourceStr, pp);
|
||||
if (r == null)
|
||||
{
|
||||
int index = pp.getErrorIndex();
|
||||
if (index < 0)
|
||||
index = pp.getIndex();
|
||||
throw new ParseException ("couldn't parse number", index);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
public final Object parseObject (String sourceStr, ParsePosition pos)
|
||||
{
|
||||
return parse (sourceStr, pos);
|
||||
}
|
||||
|
||||
public void setGroupingUsed (boolean newValue)
|
||||
{
|
||||
groupingUsed = newValue;
|
||||
}
|
||||
|
||||
public void setMaximumFractionDigits (int newValue)
|
||||
{
|
||||
maximumFractionDigits = newValue;
|
||||
}
|
||||
|
||||
public void setMaximumIntegerDigits (int newValue)
|
||||
{
|
||||
maximumIntegerDigits = newValue;
|
||||
}
|
||||
|
||||
public void setMinimumFractionDigits (int newValue)
|
||||
{
|
||||
minimumFractionDigits = newValue;
|
||||
}
|
||||
|
||||
public void setMinimumIntegerDigits (int newValue)
|
||||
{
|
||||
minimumIntegerDigits = newValue;
|
||||
}
|
||||
|
||||
public void setParseIntegerOnly (boolean value)
|
||||
{
|
||||
parseIntegerOnly = value;
|
||||
}
|
||||
|
||||
public final String format (double number)
|
||||
{
|
||||
StringBuffer sbuf = new StringBuffer(50);
|
||||
format (number, sbuf, null);
|
||||
return sbuf.toString();
|
||||
}
|
||||
|
||||
// These field names are fixed by the serialization spec.
|
||||
// FIXME: serialization spec also mentions `byte' versions of the
|
||||
// min/max fields. We have no use for those, so for now they are
|
||||
// omitted.
|
||||
protected boolean groupingUsed;
|
||||
protected int maximumFractionDigits;
|
||||
protected int maximumIntegerDigits;
|
||||
protected int minimumFractionDigits;
|
||||
protected int minimumIntegerDigits;
|
||||
protected boolean parseIntegerOnly;
|
||||
}
|
34
libjava/java/text/ParseException.java
Normal file
34
libjava/java/text/ParseException.java
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* Copyright (C) 1998, 1999 Cygnus Solutions
|
||||
|
||||
This file is part of libgcj.
|
||||
|
||||
This software is copyrighted work licensed under the terms of the
|
||||
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
||||
details. */
|
||||
|
||||
package java.text;
|
||||
|
||||
/**
|
||||
* @author Per Bothner <bothner@cygnus.com>
|
||||
* @date October 25, 1998.
|
||||
*/
|
||||
/* Written using "Java Class Libraries", 2nd edition, plus online
|
||||
* API docs for JDK 1.2 beta from http://www.javasoft.com.
|
||||
* Status: Believed complete and correct.
|
||||
*/
|
||||
|
||||
public class ParseException extends Exception
|
||||
{
|
||||
private int errorOffset;
|
||||
|
||||
public ParseException (String msg, int errorOffset)
|
||||
{
|
||||
super(msg);
|
||||
this.errorOffset = errorOffset;
|
||||
}
|
||||
|
||||
public int getErrorOffset ()
|
||||
{
|
||||
return errorOffset;
|
||||
}
|
||||
}
|
59
libjava/java/text/ParsePosition.java
Normal file
59
libjava/java/text/ParsePosition.java
Normal file
|
@ -0,0 +1,59 @@
|
|||
/* Copyright (C) 1998, 1999 Cygnus Solutions
|
||||
|
||||
This file is part of libgcj.
|
||||
|
||||
This software is copyrighted work licensed under the terms of the
|
||||
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
||||
details. */
|
||||
|
||||
package java.text;
|
||||
|
||||
/**
|
||||
* @author Per Bothner <bothner@cygnus.com>
|
||||
* @date October 25, 1998.
|
||||
*/
|
||||
/* Written using "Java Class Libraries", 2nd edition, plus online
|
||||
* API docs for JDK 1.2 beta from http://www.javasoft.com.
|
||||
* Status: Believed complete and correct.
|
||||
* Includes JDK 1.2 methods.
|
||||
*/
|
||||
|
||||
public class ParsePosition
|
||||
{
|
||||
int index;
|
||||
int errorIndex;
|
||||
|
||||
public ParsePosition (int index)
|
||||
{
|
||||
this.index = index;
|
||||
errorIndex = -1;
|
||||
}
|
||||
|
||||
public int getIndex ()
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
public void setIndex (int index)
|
||||
{
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public int getErrorIndex ()
|
||||
{
|
||||
return errorIndex;
|
||||
}
|
||||
|
||||
public void setErrorIndex (int ei)
|
||||
{
|
||||
errorIndex = ei;
|
||||
}
|
||||
|
||||
public boolean equals (Object obj)
|
||||
{
|
||||
if (obj != null || ! (obj instanceof ParsePosition))
|
||||
return false;
|
||||
ParsePosition other = (ParsePosition) obj;
|
||||
return index == other.index && errorIndex == other.errorIndex;
|
||||
}
|
||||
}
|
522
libjava/java/text/SimpleDateFormat.java
Normal file
522
libjava/java/text/SimpleDateFormat.java
Normal file
|
@ -0,0 +1,522 @@
|
|||
/* Copyright (C) 1998, 1999 Cygnus Solutions
|
||||
|
||||
This file is part of libgcj.
|
||||
|
||||
This software is copyrighted work licensed under the terms of the
|
||||
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
||||
details. */
|
||||
|
||||
package java.text;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Per Bothner <bothner@cygnus.com>
|
||||
* @date October 25, 1998.
|
||||
*/
|
||||
/* Written using "Java Class Libraries", 2nd edition, plus online
|
||||
* API docs for JDK 1.2 beta from http://www.javasoft.com.
|
||||
* Status: parse is not implemented.
|
||||
*/
|
||||
|
||||
public class SimpleDateFormat extends DateFormat
|
||||
{
|
||||
private Date defaultCenturyStart;
|
||||
private DateFormatSymbols formatData;
|
||||
private String pattern;
|
||||
|
||||
public SimpleDateFormat ()
|
||||
{
|
||||
this("dd/MM/yy HH:mm", Locale.getDefault());
|
||||
}
|
||||
|
||||
public SimpleDateFormat (String pattern)
|
||||
{
|
||||
this(pattern, Locale.getDefault());
|
||||
}
|
||||
|
||||
public SimpleDateFormat (String pattern, Locale locale)
|
||||
{
|
||||
this.pattern = pattern;
|
||||
this.calendar = Calendar.getInstance(locale);
|
||||
this.numberFormat = NumberFormat.getInstance(locale);
|
||||
numberFormat.setGroupingUsed(false);
|
||||
this.formatData = new DateFormatSymbols (locale);
|
||||
}
|
||||
|
||||
public SimpleDateFormat (String pattern, DateFormatSymbols formatData)
|
||||
{
|
||||
this.pattern = pattern;
|
||||
this.formatData = formatData;
|
||||
this.calendar = Calendar.getInstance();
|
||||
this.numberFormat = NumberFormat.getInstance();
|
||||
numberFormat.setGroupingUsed(false);
|
||||
}
|
||||
|
||||
public Date get2DigitYearStart()
|
||||
{
|
||||
return defaultCenturyStart;
|
||||
}
|
||||
|
||||
public void set2DigitYearStart(Date startDate)
|
||||
{
|
||||
defaultCenturyStart = startDate;
|
||||
}
|
||||
|
||||
public DateFormatSymbols getDateFormatSymbols ()
|
||||
{
|
||||
return formatData;
|
||||
}
|
||||
|
||||
public void setDateFormatSymbols (DateFormatSymbols value)
|
||||
{
|
||||
formatData = value;
|
||||
}
|
||||
|
||||
public String toPattern ()
|
||||
{
|
||||
return pattern;
|
||||
}
|
||||
|
||||
public void applyPattern (String pattern)
|
||||
{
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
private String applyLocalizedPattern (String pattern,
|
||||
String oldChars, String newChars)
|
||||
{
|
||||
int len = pattern.length();
|
||||
StringBuffer buf = new StringBuffer(len);
|
||||
boolean quoted = false;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
char ch = pattern.charAt(i);
|
||||
if (ch == '\'')
|
||||
quoted = ! quoted;
|
||||
if (! quoted)
|
||||
{
|
||||
int j = oldChars.indexOf(ch);
|
||||
if (j >= 0)
|
||||
ch = newChars.charAt(j);
|
||||
}
|
||||
buf.append(ch);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public void applyLocalizedPattern (String pattern)
|
||||
{
|
||||
String localChars = formatData.getLocalPatternChars();
|
||||
String standardChars = DateFormatSymbols.localPatternCharsDefault;
|
||||
pattern = applyLocalizedPattern (pattern, localChars, standardChars);
|
||||
applyPattern(pattern);
|
||||
}
|
||||
|
||||
public String toLocalizedPattern ()
|
||||
{
|
||||
String localChars = formatData.getLocalPatternChars();
|
||||
String standardChars = DateFormatSymbols.localPatternCharsDefault;
|
||||
return applyLocalizedPattern (pattern, standardChars, localChars);
|
||||
}
|
||||
|
||||
private final void append (StringBuffer buf, int value, int numDigits)
|
||||
{
|
||||
numberFormat.setMinimumIntegerDigits(numDigits);
|
||||
numberFormat.format(value, buf, null);
|
||||
}
|
||||
|
||||
public StringBuffer format (Date date, StringBuffer buf, FieldPosition pos)
|
||||
{
|
||||
Calendar calendar = (Calendar) this.calendar.clone();
|
||||
calendar.setTime(date);
|
||||
int len = pattern.length();
|
||||
int quoteStart = -1;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
char ch = pattern.charAt(i);
|
||||
if (ch == '\'')
|
||||
{
|
||||
// We must do a little lookahead to see if we have two
|
||||
// single quotes embedded in quoted text.
|
||||
if (i < len - 1 && pattern.charAt(i + 1) == '\'')
|
||||
{
|
||||
++i;
|
||||
buf.append(ch);
|
||||
}
|
||||
else
|
||||
quoteStart = quoteStart < 0 ? i : -1;
|
||||
}
|
||||
// From JCL: any characters in the pattern that are not in
|
||||
// the ranges of [a..z] and [A..Z] are treated as quoted
|
||||
// text.
|
||||
else if (quoteStart != -1
|
||||
|| ((ch < 'a' || ch > 'z')
|
||||
&& (ch < 'A' || ch > 'Z')))
|
||||
buf.append(ch);
|
||||
else
|
||||
{
|
||||
int first = i;
|
||||
int value;
|
||||
while (++i < len && pattern.charAt(i) == ch) ;
|
||||
int count = i - first; // Number of repetions of ch in pattern.
|
||||
int beginIndex = buf.length();
|
||||
int field;
|
||||
i--; // Skip all but last instance of ch in pattern.
|
||||
switch (ch)
|
||||
{
|
||||
case 'd':
|
||||
append(buf, calendar.get(Calendar.DATE), count);
|
||||
field = DateFormat.DATE_FIELD;
|
||||
break;
|
||||
case 'D':
|
||||
append(buf, calendar.get(Calendar.DAY_OF_YEAR), count);
|
||||
field = DateFormat.DAY_OF_YEAR_FIELD;
|
||||
break;
|
||||
case 'F':
|
||||
append(buf, calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH),count);
|
||||
field = DateFormat.DAY_OF_WEEK_IN_MONTH_FIELD;
|
||||
break;
|
||||
case 'E':
|
||||
value = calendar.get(calendar.DAY_OF_WEEK);
|
||||
buf.append(count <= 3 ? formatData.getShortWeekdays()[value]
|
||||
: formatData.getWeekdays()[value]);
|
||||
field = DateFormat.DAY_OF_WEEK_FIELD;
|
||||
break;
|
||||
case 'w':
|
||||
append(buf, calendar.get(Calendar.WEEK_OF_YEAR), count);
|
||||
field = DateFormat.WEEK_OF_YEAR_FIELD;
|
||||
break;
|
||||
case 'W':
|
||||
append(buf, calendar.get(Calendar.WEEK_OF_MONTH), count);
|
||||
field = DateFormat.WEEK_OF_MONTH_FIELD;
|
||||
break;
|
||||
case 'M':
|
||||
value = calendar.get(Calendar.MONTH);
|
||||
if (count <= 2)
|
||||
append(buf, value + 1, count);
|
||||
else
|
||||
buf.append(count <= 3 ? formatData.getShortMonths()[value]
|
||||
: formatData.getMonths()[value]);
|
||||
field = DateFormat.MONTH_FIELD;
|
||||
break;
|
||||
case 'y':
|
||||
value = calendar.get(Calendar.YEAR);
|
||||
append(buf, count <= 2 ? value % 100 : value, count);
|
||||
field = DateFormat.YEAR_FIELD;
|
||||
break;
|
||||
case 'K':
|
||||
append(buf, calendar.get(Calendar.HOUR), count);
|
||||
field = DateFormat.HOUR0_FIELD;
|
||||
break;
|
||||
case 'h':
|
||||
value = ((calendar.get(Calendar.HOUR) + 11) % 12) + 1;
|
||||
append(buf, value, count);
|
||||
field = DateFormat.HOUR1_FIELD;
|
||||
break;
|
||||
case 'H':
|
||||
append(buf, calendar.get(Calendar.HOUR_OF_DAY), count);
|
||||
field = DateFormat.HOUR_OF_DAY0_FIELD;
|
||||
break;
|
||||
case 'k':
|
||||
value = ((calendar.get(Calendar.HOUR_OF_DAY) + 23) % 24) + 1;
|
||||
append(buf, value, count);
|
||||
field = DateFormat.HOUR_OF_DAY1_FIELD;
|
||||
break;
|
||||
case 'm':
|
||||
append(buf, calendar.get(Calendar.MINUTE), count);
|
||||
field = DateFormat.MINUTE_FIELD;
|
||||
break;
|
||||
case 's':
|
||||
append(buf, calendar.get(Calendar.SECOND), count);
|
||||
field = DateFormat.SECOND_FIELD;
|
||||
break;
|
||||
case 'S':
|
||||
append(buf, calendar.get(Calendar.MILLISECOND), count);
|
||||
field = DateFormat.MILLISECOND_FIELD;
|
||||
break;
|
||||
case 'a':
|
||||
value = calendar.get(calendar.AM_PM);
|
||||
buf.append(formatData.getAmPmStrings()[value]);
|
||||
field = DateFormat.AM_PM_FIELD;
|
||||
break;
|
||||
case 'z':
|
||||
String zoneID = calendar.getTimeZone().getID();
|
||||
String[][] zoneStrings = formatData.getZoneStrings();
|
||||
int zoneCount = zoneStrings.length;
|
||||
for (int j = 0; j < zoneCount; j++)
|
||||
{
|
||||
String[] strings = zoneStrings[j];
|
||||
if (zoneID.equals(strings[0]))
|
||||
{
|
||||
j = count > 3 ? 2 : 1;
|
||||
if (calendar.get(Calendar.DST_OFFSET) != 0)
|
||||
j+=2;
|
||||
zoneID = strings[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
buf.append(zoneID);
|
||||
field = DateFormat.TIMEZONE_FIELD;
|
||||
break;
|
||||
default:
|
||||
// Note that the JCL is actually somewhat
|
||||
// contradictory here. It defines the pattern letters
|
||||
// to be a particular list, but also says that a
|
||||
// pattern containing an invalid pattern letter must
|
||||
// throw an exception. It doesn't describe what an
|
||||
// invalid pattern letter might be, so we just assume
|
||||
// it is any letter in [a-zA-Z] not explicitly covered
|
||||
// above.
|
||||
throw new RuntimeException("bad format string");
|
||||
}
|
||||
if (pos != null && field == pos.getField())
|
||||
{
|
||||
pos.setBeginIndex(beginIndex);
|
||||
pos.setEndIndex(buf.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
private final boolean expect (String source, ParsePosition pos,
|
||||
char ch)
|
||||
{
|
||||
int x = pos.getIndex();
|
||||
boolean r = x < source.length() && source.charAt(x) == ch;
|
||||
if (r)
|
||||
pos.setIndex(x + 1);
|
||||
else
|
||||
pos.setErrorIndex(x);
|
||||
return r;
|
||||
}
|
||||
|
||||
public Date parse (String source, ParsePosition pos)
|
||||
{
|
||||
int fmt_index = 0;
|
||||
int fmt_max = pattern.length();
|
||||
|
||||
calendar.clear();
|
||||
int quote_start = -1;
|
||||
for (; fmt_index < fmt_max; ++fmt_index)
|
||||
{
|
||||
char ch = pattern.charAt(fmt_index);
|
||||
if (ch == '\'')
|
||||
{
|
||||
int index = pos.getIndex();
|
||||
if (fmt_index < fmt_max - 1
|
||||
&& pattern.charAt(fmt_index + 1) == '\'')
|
||||
{
|
||||
if (! expect (source, pos, ch))
|
||||
return null;
|
||||
++fmt_index;
|
||||
}
|
||||
else
|
||||
quote_start = quote_start < 0 ? fmt_index : -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (quote_start != -1
|
||||
|| ((ch < 'a' || ch > 'z')
|
||||
&& (ch < 'A' || ch > 'Z')))
|
||||
{
|
||||
if (! expect (source, pos, ch))
|
||||
return null;
|
||||
continue;
|
||||
}
|
||||
|
||||
// We've arrived at a potential pattern character in the
|
||||
// pattern.
|
||||
int first = fmt_index;
|
||||
while (++fmt_index < fmt_max && pattern.charAt(fmt_index) == ch)
|
||||
;
|
||||
int count = fmt_index - first;
|
||||
--fmt_index;
|
||||
|
||||
// We can handle most fields automatically: most either are
|
||||
// numeric or are looked up in a string vector. In some cases
|
||||
// we need an offset. When numeric, `offset' is added to the
|
||||
// resulting value. When doing a string lookup, offset is the
|
||||
// initial index into the string array.
|
||||
int calendar_field;
|
||||
boolean is_numeric = true;
|
||||
String[] match = null;
|
||||
int offset = 0;
|
||||
int zone_number = 0;
|
||||
switch (ch)
|
||||
{
|
||||
case 'd':
|
||||
calendar_field = Calendar.DATE;
|
||||
break;
|
||||
case 'D':
|
||||
calendar_field = Calendar.DAY_OF_YEAR;
|
||||
break;
|
||||
case 'F':
|
||||
calendar_field = Calendar.DAY_OF_WEEK_IN_MONTH;
|
||||
break;
|
||||
case 'E':
|
||||
is_numeric = false;
|
||||
offset = 1;
|
||||
calendar_field = Calendar.DAY_OF_WEEK;
|
||||
match = (count <= 3
|
||||
? formatData.getShortWeekdays()
|
||||
: formatData.getWeekdays());
|
||||
break;
|
||||
case 'w':
|
||||
calendar_field = Calendar.WEEK_OF_YEAR;
|
||||
break;
|
||||
case 'W':
|
||||
calendar_field = Calendar.WEEK_OF_MONTH;
|
||||
break;
|
||||
case 'M':
|
||||
calendar_field = Calendar.MONTH;
|
||||
if (count <= 2)
|
||||
;
|
||||
else
|
||||
{
|
||||
is_numeric = false;
|
||||
match = (count <= 3
|
||||
? formatData.getShortMonths()
|
||||
: formatData.getMonths());
|
||||
}
|
||||
break;
|
||||
case 'y':
|
||||
calendar_field = Calendar.YEAR;
|
||||
if (count <= 2)
|
||||
offset = 1900;
|
||||
break;
|
||||
case 'K':
|
||||
calendar_field = Calendar.HOUR;
|
||||
break;
|
||||
case 'h':
|
||||
calendar_field = Calendar.HOUR;
|
||||
offset = -1;
|
||||
break;
|
||||
case 'H':
|
||||
calendar_field = Calendar.HOUR_OF_DAY;
|
||||
break;
|
||||
case 'k':
|
||||
calendar_field = Calendar.HOUR_OF_DAY;
|
||||
offset = -1;
|
||||
break;
|
||||
case 'm':
|
||||
calendar_field = Calendar.MINUTE;
|
||||
break;
|
||||
case 's':
|
||||
calendar_field = Calendar.SECOND;
|
||||
break;
|
||||
case 'S':
|
||||
calendar_field = Calendar.MILLISECOND;
|
||||
break;
|
||||
case 'a':
|
||||
is_numeric = false;
|
||||
calendar_field = Calendar.AM_PM;
|
||||
match = formatData.getAmPmStrings();
|
||||
break;
|
||||
case 'z':
|
||||
// We need a special case for the timezone, because it
|
||||
// uses a different data structure than the other cases.
|
||||
is_numeric = false;
|
||||
calendar_field = Calendar.DST_OFFSET;
|
||||
String[][] zoneStrings = formatData.getZoneStrings();
|
||||
int zoneCount = zoneStrings.length;
|
||||
int index = pos.getIndex();
|
||||
boolean found_zone = false;
|
||||
for (int j = 0; j < zoneCount; j++)
|
||||
{
|
||||
String[] strings = zoneStrings[j];
|
||||
int k;
|
||||
for (k = 1; k < strings.length; ++k)
|
||||
{
|
||||
if (source.startsWith(strings[k], index))
|
||||
break;
|
||||
}
|
||||
if (k != strings.length)
|
||||
{
|
||||
if (k > 2)
|
||||
; // FIXME: dst.
|
||||
zone_number = 0; // FIXME: dst.
|
||||
// FIXME: raw offset to SimpleTimeZone const.
|
||||
calendar.setTimeZone(new SimpleTimeZone (1, strings[0]));
|
||||
pos.setIndex(index + strings[k].length());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (! found_zone)
|
||||
{
|
||||
pos.setErrorIndex(pos.getIndex());
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pos.setErrorIndex(pos.getIndex());
|
||||
return null;
|
||||
}
|
||||
|
||||
// Compute the value we should assign to the field.
|
||||
int value;
|
||||
if (is_numeric)
|
||||
{
|
||||
numberFormat.setMinimumIntegerDigits(count);
|
||||
Number n = numberFormat.parse(source, pos);
|
||||
if (pos == null || ! (n instanceof Long))
|
||||
return null;
|
||||
value = n.intValue() + offset;
|
||||
}
|
||||
else if (match != null)
|
||||
{
|
||||
int index = pos.getIndex();
|
||||
int i;
|
||||
for (i = offset; i < match.length; ++i)
|
||||
{
|
||||
if (source.startsWith(match[i], index))
|
||||
break;
|
||||
}
|
||||
if (i == match.length)
|
||||
{
|
||||
pos.setErrorIndex(index);
|
||||
return null;
|
||||
}
|
||||
pos.setIndex(index + match[i].length());
|
||||
value = i;
|
||||
}
|
||||
else
|
||||
value = zone_number;
|
||||
|
||||
// Assign the value and move on.
|
||||
try
|
||||
{
|
||||
calendar.set(calendar_field, value);
|
||||
}
|
||||
// FIXME: what exception is thrown on an invalid
|
||||
// non-lenient set?
|
||||
catch (IllegalArgumentException x)
|
||||
{
|
||||
pos.setErrorIndex(pos.getIndex());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
public boolean equals (Object obj)
|
||||
{
|
||||
if (! (obj instanceof SimpleDateFormat) || ! super.equals(obj) )
|
||||
return false;
|
||||
SimpleDateFormat other = (SimpleDateFormat) obj;
|
||||
return (DateFormatSymbols.equals(pattern, other.pattern)
|
||||
&& DateFormatSymbols.equals(formatData, other.formatData)
|
||||
&& DateFormatSymbols.equals(defaultCenturyStart,
|
||||
other.defaultCenturyStart));
|
||||
}
|
||||
|
||||
public int hashCode ()
|
||||
{
|
||||
int hash = super.hashCode();
|
||||
if (pattern != null)
|
||||
hash ^= pattern.hashCode();
|
||||
return hash;
|
||||
}
|
||||
}
|
142
libjava/java/text/StringCharacterIterator.java
Normal file
142
libjava/java/text/StringCharacterIterator.java
Normal file
|
@ -0,0 +1,142 @@
|
|||
// StringCharacterIterator.java - Iterate over string of Unicode characters.
|
||||
|
||||
/* Copyright (C) 1999 Cygnus Solutions
|
||||
|
||||
This file is part of libgcj.
|
||||
|
||||
This software is copyrighted work licensed under the terms of the
|
||||
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
||||
details. */
|
||||
|
||||
package java.text;
|
||||
|
||||
/**
|
||||
* @author Tom Tromey <tromey@cygnus.com>
|
||||
* @date February 22, 1999
|
||||
*/
|
||||
/* Written using "Java Class Libraries", 2nd edition, plus online
|
||||
* API docs for JDK 1.2 beta from http://www.javasoft.com.
|
||||
* Status: Believed complete and correct to 1.1.
|
||||
*/
|
||||
|
||||
public final class StringCharacterIterator implements CharacterIterator
|
||||
{
|
||||
public Object clone ()
|
||||
{
|
||||
return (Object) new StringCharacterIterator (text, begin, end, pos);
|
||||
}
|
||||
|
||||
public char current ()
|
||||
{
|
||||
// This follows JDK 1.2 semantics and not 1.1 semantics.
|
||||
// In 1.1 we would throw an exception if begin==end.
|
||||
return (pos < end) ? text.charAt(pos) : CharacterIterator.DONE;
|
||||
}
|
||||
|
||||
public boolean equals (Object obj)
|
||||
{
|
||||
if (! (obj instanceof StringCharacterIterator))
|
||||
return false;
|
||||
StringCharacterIterator sci = (StringCharacterIterator) obj;
|
||||
// The spec says "the same text". We take this to mean equals,
|
||||
// not ==.
|
||||
return (pos == sci.pos
|
||||
&& begin == sci.begin
|
||||
&& end == sci.end
|
||||
&& text.equals(sci.text));
|
||||
}
|
||||
|
||||
public char first ()
|
||||
{
|
||||
pos = begin;
|
||||
return current ();
|
||||
}
|
||||
|
||||
public int getBeginIndex ()
|
||||
{
|
||||
return begin;
|
||||
}
|
||||
|
||||
public int getEndIndex ()
|
||||
{
|
||||
return end;
|
||||
}
|
||||
|
||||
public int getIndex ()
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
|
||||
public int hashCode ()
|
||||
{
|
||||
// FIXME: this is a terrible hash code. Find a better one.
|
||||
return text.hashCode() + pos + begin + end;
|
||||
}
|
||||
|
||||
public char last ()
|
||||
{
|
||||
pos = end;
|
||||
return current ();
|
||||
}
|
||||
|
||||
public char next ()
|
||||
{
|
||||
if (pos == end)
|
||||
return CharacterIterator.DONE;
|
||||
++pos;
|
||||
return current ();
|
||||
}
|
||||
|
||||
public char previous ()
|
||||
{
|
||||
if (pos == begin)
|
||||
return CharacterIterator.DONE;
|
||||
--pos;
|
||||
return current ();
|
||||
}
|
||||
|
||||
public char setIndex (int idx)
|
||||
{
|
||||
// In 1.1 we would throw an error if `idx == end'.
|
||||
if (idx < begin || idx > end)
|
||||
throw new IllegalArgumentException ();
|
||||
pos = idx;
|
||||
return current ();
|
||||
}
|
||||
|
||||
public StringCharacterIterator (String text)
|
||||
{
|
||||
// FIXME: remove check for null once we have compiler/runtime
|
||||
// support for NullPointerException.
|
||||
this (text, 0, text == null ? 0 : text.length(), 0);
|
||||
}
|
||||
public StringCharacterIterator (String text, int pos)
|
||||
{
|
||||
// FIXME: remove check for null once we have compiler/runtime
|
||||
// support for NullPointerException.
|
||||
this (text, 0, text == null ? 0 : text.length(), pos);
|
||||
}
|
||||
public StringCharacterIterator (String text, int begin, int end, int pos)
|
||||
{
|
||||
if (text == null)
|
||||
throw new NullPointerException ();
|
||||
if (begin < 0 || begin > end || end > text.length()
|
||||
// In 1.1 we would also throw if `pos == end'.
|
||||
|| pos < begin || pos > end)
|
||||
throw new IllegalArgumentException ();
|
||||
|
||||
this.text = text;
|
||||
this.begin = begin;
|
||||
this.end = end;
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
// String to iterate over.
|
||||
private String text;
|
||||
// Current position.
|
||||
private int pos;
|
||||
// Start position in string.
|
||||
private int begin;
|
||||
// End position in string.
|
||||
private int end;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue