aboutsummaryrefslogtreecommitdiff
path: root/libjava/java/util
diff options
context:
space:
mode:
authorTom Tromey <tromey@gcc.gnu.org>1999-04-07 14:42:40 +0000
committerTom Tromey <tromey@gcc.gnu.org>1999-04-07 14:42:40 +0000
commitee9dd3721be68b9fa63dea9aa5a1d86e66958cde (patch)
treed96801a16fdf03a5682ef98730fe333a46eef944 /libjava/java/util
parent140fa895c6b859f827fc4437b91775a82cd105fb (diff)
downloadgcc-ee9dd3721be68b9fa63dea9aa5a1d86e66958cde.zip
gcc-ee9dd3721be68b9fa63dea9aa5a1d86e66958cde.tar.gz
gcc-ee9dd3721be68b9fa63dea9aa5a1d86e66958cde.tar.bz2
Initial revision
From-SVN: r26263
Diffstat (limited to 'libjava/java/util')
-rw-r--r--libjava/java/util/BitSet.java183
-rw-r--r--libjava/java/util/Calendar.java258
-rw-r--r--libjava/java/util/ConcurrentModificationException.java33
-rw-r--r--libjava/java/util/Date.java460
-rw-r--r--libjava/java/util/Dictionary.java34
-rw-r--r--libjava/java/util/EmptyStackException.java27
-rw-r--r--libjava/java/util/Enumeration.java24
-rw-r--r--libjava/java/util/EventListener.java24
-rw-r--r--libjava/java/util/EventObject.java42
-rw-r--r--libjava/java/util/GregorianCalendar.java257
-rw-r--r--libjava/java/util/Hashtable.java398
-rw-r--r--libjava/java/util/ListResourceBundle.java52
-rw-r--r--libjava/java/util/Locale.java125
-rw-r--r--libjava/java/util/MissingResourceException.java43
-rw-r--r--libjava/java/util/NoSuchElementException.java32
-rw-r--r--libjava/java/util/Observable.java98
-rw-r--r--libjava/java/util/Observer.java24
-rw-r--r--libjava/java/util/Properties.java376
-rw-r--r--libjava/java/util/Random.java148
-rw-r--r--libjava/java/util/ResourceBundle.java188
-rw-r--r--libjava/java/util/SimpleTimeZone.java182
-rw-r--r--libjava/java/util/Stack.java74
-rw-r--r--libjava/java/util/StringTokenizer.java185
-rw-r--r--libjava/java/util/TimeZone.java120
-rw-r--r--libjava/java/util/TooManyListenersException.java32
-rw-r--r--libjava/java/util/Vector.java450
-rw-r--r--libjava/java/util/natDate.cc45
-rw-r--r--libjava/java/util/natGregorianCalendar.cc124
-rw-r--r--libjava/java/util/zip/Adler32.java101
-rw-r--r--libjava/java/util/zip/CRC32.java70
-rw-r--r--libjava/java/util/zip/Checksum.java31
-rw-r--r--libjava/java/util/zip/Deflater.java13
-rw-r--r--libjava/java/util/zip/DeflaterOutputStream.java46
-rw-r--r--libjava/java/util/zip/ZipConstants.java13
-rw-r--r--libjava/java/util/zip/ZipEntry.java84
-rw-r--r--libjava/java/util/zip/ZipException.java33
-rw-r--r--libjava/java/util/zip/ZipFile.java81
-rw-r--r--libjava/java/util/zip/ZipOutputStream.java26
38 files changed, 4536 insertions, 0 deletions
diff --git a/libjava/java/util/BitSet.java b/libjava/java/util/BitSet.java
new file mode 100644
index 0000000..e588695
--- /dev/null
+++ b/libjava/java/util/BitSet.java
@@ -0,0 +1,183 @@
+// BitSet - A vector of bits.
+
+/* 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.util;
+import java.io.Serializable;
+
+/**
+ * @author Tom Tromey <tromey@cygnus.com>
+ * @date October 23, 1998.
+ */
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * hashCode algorithm taken from JDK 1.2 docs.
+ */
+
+public final class BitSet implements Cloneable, Serializable
+{
+ public void and (BitSet bs)
+ {
+ if (bs == null)
+ throw new NullPointerException ();
+ int max = Math.min(bits.length, bs.bits.length);
+ int i;
+ for (i = 0; i < max; ++i)
+ bits[i] &= bs.bits[i];
+ for ( ; i < bits.length; ++i)
+ bits[i] = 0;
+ }
+
+ public BitSet ()
+ {
+ this (64);
+ }
+
+ public BitSet (int nbits)
+ {
+ if (nbits < 0)
+ throw new NegativeArraySizeException ();
+ int length = nbits / 64;
+ if (nbits % 64 != 0)
+ ++length;
+ bits = new long[length];
+ }
+
+ public void clear (int pos)
+ {
+ if (pos < 0)
+ throw new IndexOutOfBoundsException ();
+ int bit = pos % 64;
+ int offset = pos / 64;
+ ensure (offset);
+ bits[offset] &= ~ (1 << bit);
+ }
+
+ public Object clone ()
+ {
+ BitSet bs = new BitSet (bits.length * 64);
+ System.arraycopy(bits, 0, bs.bits, 0, bits.length);
+ return bs;
+ }
+
+ public boolean equals (Object obj)
+ {
+ if (! (obj instanceof BitSet))
+ return false;
+ BitSet bs = (BitSet) obj;
+ int max = Math.min(bits.length, bs.bits.length);
+ int i;
+ for (i = 0; i < max; ++i)
+ if (bits[i] != bs.bits[i])
+ return false;
+ // If one is larger, check to make sure all extra bits are 0.
+ for (int j = i; j < bits.length; ++j)
+ if (bits[j] != 0)
+ return false;
+ for (int j = i; j < bs.bits.length; ++j)
+ if (bs.bits[j] != 0)
+ return false;
+ return true;
+ }
+
+ public boolean get (int pos)
+ {
+ if (pos < 0)
+ throw new IndexOutOfBoundsException ();
+
+ int bit = pos % 64;
+ int offset = pos / 64;
+
+ if (offset >= bits.length)
+ return false;
+
+ return (bits[offset] & (1 << bit)) == 0 ? false : true;
+ }
+
+ public int hashCode ()
+ {
+ long h = 1234;
+ for (int i = bits.length - 1; i >= 0; --i)
+ h ^= bits[i] * (i + 1);
+ return (int) ((h >> 32) ^ h);
+ }
+
+ public void or (BitSet bs)
+ {
+ if (bs == null)
+ throw new NullPointerException ();
+ ensure (bs.bits.length - 1);
+ int i;
+ for (i = 0; i < bs.bits.length; ++i)
+ bits[i] |= bs.bits[i];
+ }
+
+ public void set (int pos)
+ {
+ if (pos < 0)
+ throw new IndexOutOfBoundsException ();
+ int bit = pos % 64;
+ int offset = pos / 64;
+ ensure (offset);
+ bits[offset] |= 1 << bit;
+ }
+
+ public int size ()
+ {
+ return bits.length * 64;
+ }
+
+ public String toString ()
+ {
+ StringBuffer result = new StringBuffer ("{");
+ boolean first = true;
+ for (int i = 0; i < bits.length; ++i)
+ {
+ int bit = 1;
+ long word = bits[i];
+ for (int j = 0; j < 64; ++j)
+ {
+ if ((word & bit) != 0)
+ {
+ if (! first)
+ result.append(", ");
+ result.append(64 * i + j);
+ first = false;
+ }
+ bit <<= 1;
+ }
+ }
+
+ return result.append("}").toString();
+ }
+
+ public void xor (BitSet bs)
+ {
+ if (bs == null)
+ throw new NullPointerException ();
+ ensure (bs.bits.length - 1);
+ int i;
+ for (i = 0; i < bs.bits.length; ++i)
+ bits[i] ^= bs.bits[i];
+ }
+
+ // Make sure the vector is big enough.
+ private final void ensure (int lastElt)
+ {
+ if (lastElt + 1 > bits.length)
+ {
+ long[] nd = new long[lastElt + 1];
+ System.arraycopy(bits, 0, nd, 0, bits.length);
+ bits = nd;
+ }
+ }
+
+ // The actual bits.
+ private long[] bits;
+}
diff --git a/libjava/java/util/Calendar.java b/libjava/java/util/Calendar.java
new file mode 100644
index 0000000..8649adf
--- /dev/null
+++ b/libjava/java/util/Calendar.java
@@ -0,0 +1,258 @@
+/* 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.util;
+
+/**
+ * @author Per Bothner <bothner@cygnus.com>
+ * @date October 24, 1998.
+ */
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3,
+ * and "The Java Language Specification", ISBN 0-201-63451-1.
+ * Status: Unimplemented: getAvailableLocales.
+ * No Locale knowledge.
+ */
+
+public abstract class Calendar implements java.io.Serializable, Cloneable
+{
+ public final static int JANUARY = 0;
+ public final static int FEBRUARY = 1;
+ public final static int MARCH = 2;
+ public final static int APRIL = 3;
+ public final static int MAY = 4;
+ public final static int JUNE = 5;
+ public final static int JULY = 6;
+ public final static int AUGUST = 7;
+ public final static int SEPTEMBER = 8;
+ public final static int OCTOBER = 9;
+ public final static int NOVEMBER = 10;
+ public final static int DECEMBER = 11;
+ public final static int UNDECIMBER = 12;
+
+ public final static int SUNDAY = 1;
+ public final static int MONDAY = 2;
+ public final static int TUESDAY = 3;
+ public final static int WEDNESDAY = 4;
+ public final static int THURSDAY = 5;
+ public final static int FRIDAY = 6;
+ public final static int SATURDAY = 7;
+
+ public final static int AM = 0;
+ public final static int PM = 1;
+
+ public final static int FIELD_COUNT = 17;
+
+ // These constants are not docuemnted, but were determined using
+ // a simple test program.
+ public final static int ERA = 0;
+ public final static int YEAR = 1;
+ public final static int MONTH = 2;
+ public final static int WEEK_OF_YEAR = 3;
+ public final static int WEEK_OF_MONTH = 4;
+ public final static int DATE = 5;
+ public final static int DAY_OF_MONTH = 5;
+ public final static int DAY_OF_YEAR = 6;
+ public final static int DAY_OF_WEEK = 7;
+ public final static int DAY_OF_WEEK_IN_MONTH = 8;
+ public final static int AM_PM = 9;
+ public final static int HOUR = 10;
+ public final static int HOUR_OF_DAY = 11;
+ public final static int MINUTE = 12;
+ public final static int SECOND = 13;
+ public final static int MILLISECOND = 14;
+ public final static int ZONE_OFFSET = 15;
+ public final static int DST_OFFSET = 16;
+
+ // The fields are as specified in Sun's "Serialized Form"
+ // in the JDK 1.2 beta 4 API specification.
+ protected boolean areFieldsSet;
+ protected int[] fields;
+ private int firstDayOfWeek;
+ protected boolean[] isSet;
+ protected boolean isTimeSet;
+ private boolean lenient;
+ private int minimalDaysInFirstWeek;
+ private int nextStamp;
+ //private int serialVersionOnStream;
+ protected long time;
+ private TimeZone zone;
+
+ protected Calendar ()
+ {
+ this (null, null);
+ }
+
+ protected Calendar (TimeZone tx, Locale loc)
+ {
+ fields = new int[FIELD_COUNT];
+ isSet = new boolean[FIELD_COUNT];
+ firstDayOfWeek = SUNDAY; // Locale-dependent. FIXME.
+ this.zone = zone != null ? zone : TimeZone.getDefault();
+ }
+
+ public Object clone ()
+ {
+ try
+ {
+ return super.clone();
+ }
+ catch (CloneNotSupportedException ex)
+ {
+ throw new RuntimeException("internal error - "+ex);
+ }
+ }
+
+ public static Calendar getInstance ()
+ {
+ return new GregorianCalendar ();
+ }
+
+ public static Calendar getInstance (TimeZone zone)
+ {
+ return new GregorianCalendar (zone);
+ }
+
+ public static Calendar getInstance (Locale locale)
+ {
+ return new GregorianCalendar (locale);
+ }
+
+ public static Calendar getInstance (TimeZone zone, Locale locale)
+ {
+ return new GregorianCalendar (zone, locale);
+ }
+
+ public boolean isLenient() { return lenient; }
+ public void setLenient (boolean lenient) { this.lenient = lenient; }
+
+ public int getFirstDayOfWeek ()
+ {
+ return firstDayOfWeek;
+ }
+
+ public void setFirstDayOfWeek (int value)
+ {
+ firstDayOfWeek = value;
+ }
+
+ public int getMinimalDaysInFirstWeek ()
+ {
+ return minimalDaysInFirstWeek;
+ }
+
+ public void setMinimalDaysInFirstWeek (int value)
+ {
+ minimalDaysInFirstWeek = value;
+ }
+
+ public TimeZone getTimeZone ()
+ {
+ return zone;
+ }
+
+ public void setTimeZone (TimeZone tz)
+ {
+ zone = tz;
+ }
+
+ abstract public void add(int fld, int amount);
+ abstract public void roll (int fld, boolean up);
+
+ public final void set (int year, int month, int date)
+ {
+ set(YEAR, year);
+ set(MONTH, month);
+ set(DATE, date);
+ }
+
+ public final void set (int year, int month, int date, int hour, int minute)
+ {
+ set(year, month, date);
+ set(HOUR_OF_DAY, hour);
+ set(MINUTE, minute);
+ }
+
+ public final void set (int year, int month, int date,
+ int hour, int minute, int second)
+ {
+ set(year, month, date, hour, minute);
+ set(SECOND, second);
+ }
+
+ public final void set (int fld, int value)
+ {
+ fields[fld] = value;
+ isTimeSet = false;
+ }
+
+ public final void clear (int fld)
+ {
+ fields[fld] = 0;
+ isSet[fld] = false;
+ areFieldsSet = false;
+ }
+
+ public final void clear ()
+ {
+ for (int fld = FIELD_COUNT; --fld >= 0; )
+ {
+ fields[fld] = 0;
+ isSet[fld] = false;
+ }
+ areFieldsSet = false;
+ }
+
+ protected void complete()
+ {
+ if (!isTimeSet) computeTime();
+ if (!areFieldsSet) computeFields();
+ }
+
+ protected abstract void computeFields();
+ protected abstract void computeTime();
+
+ protected final int internalGet (int fld) { return fields[fld]; }
+
+ public final int get(int fld)
+ {
+ complete();
+ return fields[fld];
+ }
+
+ public abstract boolean after (Object cal);
+ public abstract boolean before (Object cal);
+ public abstract boolean equals (Object obj);
+
+ protected long getTimeInMillis()
+ {
+ if (!isTimeSet) computeTime();
+ return time;
+ }
+
+ public final Date getTime() { return new Date(getTimeInMillis()); }
+
+ public final void setTime (Date date)
+ {
+ setTimeInMillis(date.getTime());
+ }
+
+ protected void setTimeInMillis (long millis)
+ {
+ time = millis;
+ isTimeSet = true;
+ clear();
+ }
+
+ abstract public int getMaximum(int fld);
+ abstract public int getMinimum(int fld);
+ abstract public int getGreatestMinimum(int fld);
+ abstract public int getLeastMaximum(int fld);
+
+ public final boolean isSet(int fld) { return isSet[fld]; }
+}
diff --git a/libjava/java/util/ConcurrentModificationException.java b/libjava/java/util/ConcurrentModificationException.java
new file mode 100644
index 0000000..478fdff
--- /dev/null
+++ b/libjava/java/util/ConcurrentModificationException.java
@@ -0,0 +1,33 @@
+/* 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.util;
+
+/**
+ * @author Warren Levy <warrenl@cygnus.com>
+ * @date September 2, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ */
+
+/* Added in JDK 1.2 */
+public class ConcurrentModificationException extends RuntimeException
+{
+ public ConcurrentModificationException()
+ {
+ super();
+ }
+
+ public ConcurrentModificationException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/libjava/java/util/Date.java b/libjava/java/util/Date.java
new file mode 100644
index 0000000..3d23780
--- /dev/null
+++ b/libjava/java/util/Date.java
@@ -0,0 +1,460 @@
+/* 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.util;
+import java.text.*;
+
+/**
+ * @author Per Bothner <bothner@cygnus.com>
+ * @date October 24, 1998.
+ */
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3,
+ * "The Java Language Specification", ISBN 0-201-63451-1,
+ * and O'Reilly's "Java in a Nutshell".
+ * Status: Need to re-write toString().
+ * Missing: ToGMTString and toLocaleString.
+ * Serialization spec: Specifies readObject/writeObject.
+ */
+
+public class Date implements java.io.Serializable, Cloneable
+{
+ private long millis;
+
+ public Date() { millis = System.currentTimeMillis(); }
+
+ public Date(long millis) { this.millis = millis; }
+
+ public Date(int year, int month, int date, int hours,
+ int minutes, int seconds)
+ {
+ setTime(year, month, date, hours, minutes, seconds);
+ }
+
+ public Date(int year, int month, int date, int hours, int minutes)
+ {
+ setTime(year, month, date, hours, minutes, 0);
+ }
+
+ public Date(int year, int month, int date)
+ {
+ setTime(year, month, date, 0, 0, 0);
+ }
+
+ public Date (String s) { this(parse(s)); }
+
+ private static int skipParens(String string, int offset)
+ {
+ int len = string.length();
+ int p = 0;
+ int i;
+
+ for (i = offset; i < len; ++i)
+ {
+ if (string.charAt(i) == '(')
+ ++p;
+ else if (string.charAt(i) == ')')
+ {
+ --p;
+ if (p == 0)
+ return i + 1;
+ // If we've encounted unbalanced parens, just return the
+ // leftover one as an ordinary character. It will be
+ // caught later in parsing and cause an
+ // IllegalArgumentException.
+ if (p < 0)
+ return i;
+ }
+ }
+
+ // Not sure what to do if `p != 0' here.
+ return i;
+ }
+
+ private static int parseTz(String tok, char sign)
+ throws IllegalArgumentException
+ {
+ int num;
+
+ try
+ {
+ // parseInt doesn't handle '+' so strip off sign.
+ num = Integer.parseInt(tok.substring(1));
+ }
+ catch (NumberFormatException ex)
+ {
+ throw new IllegalArgumentException(tok);
+ }
+
+ // Convert hours to minutes.
+ if (num < 24)
+ num *= 60;
+ else
+ num = (num / 100) * 60 + num % 100;
+
+ return sign == '-' ? -num : num;
+ }
+
+ private static int parseMonth(String tok)
+ {
+ // Initialize strings for month names.
+ // We could possibly use the fields of DateFormatSymbols but that is
+ // localized and thus might not match the English words specified.
+ String months[] = { "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY",
+ "JUNE", "JULY", "AUGUST", "SEPTEMBER", "OCTOBER",
+ "NOVEMBER", "DECEMBER" };
+
+ int i;
+ for (i = 0; i < 12; i++)
+ if (months[i].startsWith(tok))
+ return i;
+
+ // Return -1 if not found.
+ return -1;
+ }
+
+ private static boolean parseDayOfWeek(String tok)
+ {
+ // Initialize strings for days of the week names.
+ // We could possibly use the fields of DateFormatSymbols but that is
+ // localized and thus might not match the English words specified.
+ String daysOfWeek[] = { "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY",
+ "THURSDAY", "FRIDAY", "SATURDAY" };
+
+ int i;
+ for (i = 0; i < 7; i++)
+ if (daysOfWeek[i].startsWith(tok))
+ return true;
+
+ return false;
+ }
+
+ public static long parse(String string)
+ {
+ // Initialize date/time fields before parsing begins.
+ int year = -1;
+ int month = -1;
+ int day = -1;
+ int hour = -1;
+ int minute = -1;
+ int second = -1;
+ int timezone = 0;
+ boolean localTimezone = true;
+
+ // Trim out any nested stuff in parentheses now to make parsing easier.
+ StringBuffer buf = new StringBuffer();
+ int off = 0;
+ int openParenOffset, tmpMonth;
+ while ((openParenOffset = string.indexOf('(', off)) >= 0)
+ {
+ // Copy part of string leading up to open paren.
+ buf.append(string.substring(off, openParenOffset));
+ off = skipParens(string, openParenOffset);
+ }
+ buf.append(string.substring(off));
+
+ // Make all chars upper case to simplify comparisons later.
+ // Also ignore commas; treat them as delimiters.
+ StringTokenizer strtok =
+ new StringTokenizer(buf.toString().toUpperCase(), " \t\n\r,");
+
+ while (strtok.hasMoreTokens())
+ {
+ String tok = strtok.nextToken();
+ char firstch = tok.charAt(0);
+ if ((firstch == '+' || firstch == '-') && year >= 0)
+ {
+ timezone = parseTz(tok, firstch);
+ localTimezone = false;
+ }
+ else if (firstch >= '0' && firstch <= '9')
+ {
+ while (tok != null && tok.length() > 0)
+ {
+ // A colon or slash may be valid in the number.
+ // Find the first of these before calling parseInt.
+ int colon = tok.indexOf(':');
+ int slash = tok.indexOf('/');
+ int hyphen = tok.indexOf('-');
+ // We choose tok.length initially because it makes
+ // processing simpler.
+ int punctOffset = tok.length();
+ if (colon >= 0)
+ punctOffset = Math.min(punctOffset, colon);
+ if (slash >= 0)
+ punctOffset = Math.min(punctOffset, slash);
+ if (hyphen >= 0)
+ punctOffset = Math.min(punctOffset, hyphen);
+ // Following code relies on -1 being the exceptional
+ // case.
+ if (punctOffset == tok.length())
+ punctOffset = -1;
+
+ int num;
+ try
+ {
+ num = Integer.parseInt(punctOffset < 0 ? tok :
+ tok.substring(0, punctOffset));
+ }
+ catch (NumberFormatException ex)
+ {
+ throw new IllegalArgumentException(tok);
+ }
+
+ // TBD: Spec says year can be followed by a slash. That might
+ // make sense if using YY/MM/DD formats, but it would fail in
+ // that format for years <= 70. Also, what about 1900? That
+ // is interpreted as the year 3800; seems that the comparison
+ // should be num >= 1900 rather than just > 1900.
+ // What about a year of 62 - 70? (61 or less could be a (leap)
+ // second). 70/MM/DD cause an exception but 71/MM/DD is ok
+ // even though there's no ambiguity in either case.
+ // For the parse method, the spec as written seems too loose.
+ // Until shown otherwise, we'll follow the spec as written.
+ if (num > 70 && (punctOffset < 0 || punctOffset == slash))
+ year = num > 1900 ? num - 1900 : num;
+ else if (punctOffset > 0 && punctOffset == colon)
+ {
+ if (hour < 0)
+ hour = num;
+ else
+ minute = num;
+ }
+ else if (punctOffset > 0 && punctOffset == slash)
+ {
+ if (month < 0)
+ month = num - 1;
+ else
+ day = num;
+ }
+ else if (hour >= 0 && minute < 0)
+ minute = num;
+ else if (minute >= 0 && second < 0)
+ second = num;
+ else if (day < 0)
+ day = num;
+ else
+ throw new IllegalArgumentException(tok);
+
+ // Advance string if there's more to process in this token.
+ if (punctOffset < 0 || punctOffset + 1 >= tok.length())
+ tok = null;
+ else
+ tok = tok.substring(punctOffset + 1);
+ }
+ }
+ else if (firstch >= 'A' && firstch <= 'Z')
+ {
+ if (tok.equals("AM"))
+ {
+ if (hour < 1 || hour > 12)
+ throw new IllegalArgumentException(tok);
+ if (hour == 12)
+ hour = 0;
+ }
+ else if (tok.equals("PM"))
+ {
+ if (hour < 1 || hour > 12)
+ throw new IllegalArgumentException(tok);
+ if (hour < 12)
+ hour += 12;
+ }
+ else if (parseDayOfWeek(tok))
+ ; // Ignore it; throw the token away.
+ else if (tok.equals("UT") || tok.equals("UTC") || tok.equals("GMT"))
+ localTimezone = false;
+ else if (tok.startsWith("UT") || tok.startsWith("GMT"))
+ {
+ int signOffset = 3;
+ if (tok.charAt(1) == 'T' && tok.charAt(2) != 'C')
+ signOffset = 2;
+
+ char sign = tok.charAt(signOffset);
+ if (sign != '+' && sign != '-')
+ throw new IllegalArgumentException(tok);
+
+ timezone = parseTz(tok.substring(signOffset), sign);
+ localTimezone = false;
+ }
+ else if ((tmpMonth = parseMonth(tok)) >= 0)
+ month = tmpMonth;
+ else if (tok.length() == 3 && tok.charAt(2) == 'T')
+ {
+ // Convert timezone offset from hours to minutes.
+ char ch = tok.charAt(0);
+ if (ch == 'E')
+ timezone = -5 * 60;
+ else if (ch == 'C')
+ timezone = -6 * 60;
+ else if (ch == 'M')
+ timezone = -7 * 60;
+ else if (ch == 'P')
+ timezone = -8 * 60;
+ else
+ throw new IllegalArgumentException(tok);
+
+ // Shift 60 minutes for Daylight Savings Time.
+ if (tok.charAt(1) == 'D')
+ timezone += 60;
+ else if (tok.charAt(1) != 'S')
+ throw new IllegalArgumentException(tok);
+
+ localTimezone = false;
+ }
+ else
+ throw new IllegalArgumentException(tok);
+ }
+ else
+ throw new IllegalArgumentException(tok);
+ }
+
+ // Unspecified minutes and seconds should default to 0.
+ if (minute < 0)
+ minute = 0;
+ if (second < 0)
+ second = 0;
+
+ // Throw exception if any other fields have not been recognized and set.
+ if (year < 0 || month < 0 || day < 0 || hour < 0)
+ throw new IllegalArgumentException("Missing field");
+
+ // Return the time in either local time or relative to GMT as parsed.
+ // If no time-zone was specified, get the local one (in minutes) and
+ // convert to milliseconds before adding to the UTC.
+ return UTC(year, month, day, hour, minute, second) + (localTimezone ?
+ new Date(year, month, day).getTimezoneOffset() * 60 * 1000:
+ -timezone * 60 * 1000);
+ }
+
+ public boolean after (Date when) { return this.millis > when.millis; }
+ public boolean before (Date when) { return this.millis < when.millis; }
+
+ public boolean equals(Object obj)
+ {
+ return (obj != null && obj instanceof Date
+ && ((Date)obj).millis == this.millis);
+ }
+
+ public long getTime() { return millis; }
+
+ public int hashCode()
+ {
+ return (int)(millis^(millis>>>32));
+ }
+
+ private void setTime(int year, int month, int date,
+ int hours, int minutes, int seconds)
+ {
+ Calendar cal = new GregorianCalendar(year+1900, month, date,
+ hours, minutes, seconds);
+ millis = cal.getTimeInMillis();
+ }
+
+ public void setTime(long millis) { this.millis = millis; }
+
+ private int getField (int fld)
+ {
+ Calendar cal = new GregorianCalendar();
+ cal.setTime(this);
+ return cal.get(fld);
+ }
+
+ public int getYear ()
+ {
+ return getField(Calendar.YEAR) - 1900;
+ }
+
+ public int getMonth ()
+ {
+ return getField(Calendar.MONTH);
+ }
+
+ public int getDate ()
+ {
+ return getField(Calendar.DATE);
+ }
+
+ public int getDay ()
+ {
+ return getField(Calendar.DAY_OF_WEEK) - 1;
+ }
+
+ public int getHours ()
+ {
+ return getField(Calendar.HOUR_OF_DAY);
+ }
+
+ public int getMinutes ()
+ {
+ return getField(Calendar.MINUTE);
+ }
+
+ public int getSeconds ()
+ {
+ return getField(Calendar.SECOND);
+ }
+
+ private void setField (int fld, int value)
+ {
+ Calendar cal = new GregorianCalendar();
+ cal.setTime(this);
+ cal.set(fld, value);
+ millis = cal.getTimeInMillis();
+ }
+
+ public void setYear (int year)
+ {
+ setField(Calendar.YEAR, 1900 + year);
+ }
+
+ public void setMonth (int month)
+ {
+ setField(Calendar.MONTH, month);
+ }
+
+ public void setDate (int date)
+ {
+ setField(Calendar.DATE, date);
+ }
+
+ public void setHours (int hours)
+ {
+ setField(Calendar.HOUR_OF_DAY, hours);
+ }
+
+ public void setMinutes (int minutes)
+ {
+ setField(Calendar.MINUTE, minutes);
+ }
+
+ public void setSeconds (int seconds)
+ {
+ setField(Calendar.SECOND, seconds);
+ }
+
+ public int getTimezoneOffset ()
+ {
+ Calendar cal = new GregorianCalendar();
+ cal.setTime(this);
+ return - (cal.get(Calendar.ZONE_OFFSET)
+ + cal.get(Calendar.DST_OFFSET)/(60*1000));
+ }
+
+ public native String toString ();
+
+ // TODO: toLocaleString
+ // TODO: toGMTString
+
+ public static long UTC (int year, int month, int date,
+ int hours, int minutes, int seconds)
+ {
+ GregorianCalendar cal = new GregorianCalendar (TimeZone.zoneGMT);
+ cal.set(year+1900, month, date, hours, minutes, seconds);
+ return cal.getTimeInMillis();
+ }
+}
diff --git a/libjava/java/util/Dictionary.java b/libjava/java/util/Dictionary.java
new file mode 100644
index 0000000..2c27112
--- /dev/null
+++ b/libjava/java/util/Dictionary.java
@@ -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.util;
+
+/**
+ * @author Warren Levy <warrenl@cygnus.com>
+ * @date August 31, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct
+ */
+
+/* The JDK 1.2 beta doc indicates that Dictionary is obsolete and that the
+ * new java.util.Map interface should be used instead.
+ */
+public abstract class Dictionary
+{
+ public abstract Enumeration elements();
+ public abstract Object get(Object key) throws NullPointerException;
+ public abstract boolean isEmpty();
+ public abstract Enumeration keys();
+ public abstract Object put(Object key, Object elem)
+ throws NullPointerException;
+ public abstract Object remove(Object key) throws NullPointerException;
+ public abstract int size();
+}
diff --git a/libjava/java/util/EmptyStackException.java b/libjava/java/util/EmptyStackException.java
new file mode 100644
index 0000000..9c4c0b0
--- /dev/null
+++ b/libjava/java/util/EmptyStackException.java
@@ -0,0 +1,27 @@
+/* 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.util;
+
+/**
+ * @author Warren Levy <warrenl@cygnus.com>
+ * @date September 2, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ */
+
+public class EmptyStackException extends RuntimeException
+{
+ public EmptyStackException()
+ {
+ super();
+ }
+}
diff --git a/libjava/java/util/Enumeration.java b/libjava/java/util/Enumeration.java
new file mode 100644
index 0000000..2332888
--- /dev/null
+++ b/libjava/java/util/Enumeration.java
@@ -0,0 +1,24 @@
+/* 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.util;
+
+/**
+ * @author Warren Levy <warrenl@cygnus.com>
+ * @date August 25, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1.
+ * Status: Believed complete and correct
+ */
+
+public interface Enumeration
+{
+ public boolean hasMoreElements();
+ public Object nextElement() throws NoSuchElementException;
+}
diff --git a/libjava/java/util/EventListener.java b/libjava/java/util/EventListener.java
new file mode 100644
index 0000000..394d98c
--- /dev/null
+++ b/libjava/java/util/EventListener.java
@@ -0,0 +1,24 @@
+// EventListener.java - Listen for events from event source.
+
+/* 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.util;
+
+/**
+ * @author Tom Tromey <tromey@cygnus.com>
+ * @date December 12, 1998
+ */
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * Status: Believed complete and correct.
+ */
+
+public interface EventListener
+{
+}
diff --git a/libjava/java/util/EventObject.java b/libjava/java/util/EventObject.java
new file mode 100644
index 0000000..178ecff
--- /dev/null
+++ b/libjava/java/util/EventObject.java
@@ -0,0 +1,42 @@
+// EventObject.java - Represent events fired by objects.
+
+/* 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.util;
+
+/**
+ * @author Tom Tromey <tromey@cygnus.com>
+ * @date December 12, 1998
+ */
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * Status: Believed complete, but not fully correct.
+ */
+
+public class EventObject implements java.io.Serializable
+{
+ public EventObject (Object source)
+ {
+ this.source = source;
+ }
+
+ public Object getSource ()
+ {
+ return source;
+ }
+
+ public String toString ()
+ {
+ // FIXME.
+ return getSource().toString();
+ }
+
+ // Source of the event.
+ protected transient Object source;
+}
diff --git a/libjava/java/util/GregorianCalendar.java b/libjava/java/util/GregorianCalendar.java
new file mode 100644
index 0000000..d20c06e
--- /dev/null
+++ b/libjava/java/util/GregorianCalendar.java
@@ -0,0 +1,257 @@
+/* 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.util;
+
+/**
+ * @author Per Bothner <bothner@cygnus.com>
+ * @date October 24, 1998.
+ */
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3,
+ * and "The Java Language Specification", ISBN 0-201-63451-1.
+ * Status: "leniency" is not handled, and neither is roll-over in
+ * add and roll. This is partly because of unclear specification.
+ * hashCode has no spec.
+ */
+
+public class GregorianCalendar extends Calendar {
+ public static final int BC = 0;
+ public static final int AD = 1;
+
+ // The fields are as specified in Sun's "Serialized Form"
+ // in the JDK 1.2 beta 4 API specification.
+ // Value from a simple test program (getGregorianChange.getTime()).
+ long gregorianCutover = -12219292800000L;
+
+ private final static int[] mins = {
+ 0 /* ERA */,
+ 1 /* YEAR */,
+ 0 /* MONTH */,
+ 0 /* WEEK_OF_YEAR */,
+ 0 /* WEEK_OF_MONTH */,
+ 1 /* DATE */,
+ 1 /* DAY_OF_YEAR */,
+ 1 /* DAY_OF_WEEK */,
+ -1 /* DAY_OF_WEEK_IN_MONTH */,
+ 0 /* AM_PM */,
+ 0 /* HOUR */,
+ 0 /* HOUR_OF_DAY */,
+ 0 /* MINUTE */,
+ 0 /* SECOND */,
+ 0 /* MILLISECOND */,
+ -43200000 /* ZONE_OFFSET */,
+ 0 /* DST_OFFSET */
+ };
+
+ private final static int[] maxs = {
+ 1 /* ERA */,
+ 5000000 /* YEAR */,
+ 11 /* MONTH */,
+ 54 /* WEEK_OF_YEAR */,
+ 6 /* WEEK_OF_MONTH */,
+ 31 /* DATE */,
+ 366 /* DAY_OF_YEAR */,
+ 7 /* DAY_OF_WEEK */,
+ 6 /* DAY_OF_WEEK_IN_MONTH */,
+ 1 /* AM_PM */,
+ 12 /* HOUR */,
+ 23 /* HOUR_OF_DAY */,
+ 59 /* MINUTE */,
+ 59 /* SECOND */,
+ 999 /* MILLISECOND */,
+ 43200000 /* ZONE_OFFSET */,
+ 3600000 /* DST_OFFSET */
+ };
+
+ private final static int[] leastMaximums = {
+ 1 /* ERA */,
+ 5000000 /* YEAR */,
+ 11 /* MONTH */,
+ 53 /* WEEK_OF_YEAR */,
+ 6 /* WEEK_OF_MONTH */,
+ 28 /* DATE */,
+ 365 /* DAY_OF_YEAR */,
+ 7 /* DAY_OF_WEEK */,
+ 4 /* DAY_OF_WEEK_IN_MONTH */,
+ 1 /* AM_PM */,
+ 11 /* HOUR */,
+ 23 /* HOUR_OF_DAY */,
+ 59 /* MINUTE */,
+ 59 /* SECOND */,
+ 999 /* MILLISECOND */,
+ 43200000 /* ZONE_OFFSET */,
+ 3600000 /* DST_OFFSET */
+ };
+
+ public GregorianCalendar ()
+ {
+ this(null, null);
+ }
+
+ public GregorianCalendar (TimeZone zone)
+ {
+ this (zone, null);
+ }
+
+ public GregorianCalendar (Locale locale)
+ {
+ this (null, locale);
+ }
+
+ public GregorianCalendar (TimeZone zone, Locale locale)
+ {
+ super (zone, locale);
+ }
+
+ public GregorianCalendar (int year, int month, int date)
+ {
+ this((TimeZone) null);
+ set (year, month, date);
+ }
+
+ public GregorianCalendar (int year, int month, int date,
+ int hour, int minute)
+ {
+ this((TimeZone) null);
+ set (year, month, date, hour, minute);
+ }
+
+ public GregorianCalendar (int year, int month, int date,
+ int hour, int minute, int second)
+ {
+ this((TimeZone) null);
+ set (year, month, date, hour, minute, second);
+ }
+
+ public int getMinimum(int calfield) { return mins[calfield]; }
+ public int getGreatestMinimum(int calfield) { return mins[calfield]; }
+ public int getMaximum(int calfield) { return maxs[calfield]; }
+ public int getLeastMaximum(int calfield) { return leastMaximums[calfield]; }
+
+ protected native void computeFields();
+
+ protected native void computeTime();
+
+ public void add (int fld, int amount)
+ {
+ if (fld >= ZONE_OFFSET)
+ throw new IllegalArgumentException("bad field to add");
+ fields[fld] += amount;
+ adjust(fld);
+ }
+
+ public void roll (int fld, boolean up)
+ {
+ if (fld >= ZONE_OFFSET)
+ throw new IllegalArgumentException("bad field to roll");
+
+ int old = fields[fld];
+ if (up)
+ {
+ fields[fld] = old == getMaximum(fld) ? getMinimum(fld)
+ : old + 1;
+ }
+ else
+ {
+ fields[fld] = old == getMinimum(fld) ? getMaximum(fld)
+ : old - 1;
+ }
+ }
+
+ private void adjust (int fld)
+ {
+ int value = fields[fld];
+ int radix = maxs[fld] + 1;
+ switch (fld)
+ {
+ case MONTH:
+ case SECOND:
+ case MILLISECOND:
+ if (value >= radix)
+ {
+ int next = value / radix;
+ fields[fld] = value - radix * next;
+ fields[fld - 1] += next;
+ adjust(fld - 1);
+ }
+ else if (value < 0) // min[fld]
+ {
+ int next = (value - radix - 1) / radix;
+ fields[fld] = value - radix * next;
+ fields[fld - 1] += next;
+ adjust(fld - 1);
+ }
+ break;
+ }
+ }
+
+ public final Date getGregorianChange() { return new Date(gregorianCutover); }
+ public void setGregorianChange (Date date)
+ { gregorianCutover = date.getTime(); }
+
+ public boolean isLeapYear(int year)
+ {
+ if ((year % 4) != 0)
+ return false;
+ if ((year % 100) != 0 || (year % 400) == 0)
+ return true;
+ // year divisible by 100 but not 400.
+ GregorianCalendar date = new GregorianCalendar(year, FEBRUARY, 28);
+ return gregorianCutover < date.getTimeInMillis();
+ }
+
+ public boolean after (Object cal)
+ {
+ return cal instanceof Calendar
+ && getTimeInMillis() > ((Calendar) cal).getTimeInMillis();
+ }
+
+ public boolean before (Object cal)
+ {
+ return cal instanceof Calendar
+ && getTimeInMillis() < ((Calendar) cal).getTimeInMillis();
+ }
+
+ public boolean equals (Object obj)
+ {
+ if (obj == null || ! (obj instanceof GregorianCalendar))
+ return false;
+ GregorianCalendar other = (GregorianCalendar) obj;
+
+ for (int i = FIELD_COUNT; --i >= 0; )
+ {
+ boolean set = isSet[i];
+ if (set != other.isSet[i]
+ || (set && fields[i] != other.fields[i]))
+ return false;
+ }
+ if (areFieldsSet != other.areFieldsSet
+ || isTimeSet != other.isTimeSet
+ || (isTimeSet && time != other.time)
+ || getFirstDayOfWeek() != other.getFirstDayOfWeek()
+ || getMinimalDaysInFirstWeek() != other.getMinimalDaysInFirstWeek()
+ || isLenient() != other.isLenient()
+ || ! getTimeZone().equals(other.getTimeZone()))
+ return false;
+ return true;
+ }
+
+ public int hashCode ()
+ {
+ int hashcode = 0;
+ for (int i = FIELD_COUNT; --i >= 0; )
+ {
+ if (isSet[i])
+ hashcode += 37 * fields[i];
+ }
+ if (isTimeSet)
+ hashcode += 89 * time;
+ return hashcode;
+ }
+}
diff --git a/libjava/java/util/Hashtable.java b/libjava/java/util/Hashtable.java
new file mode 100644
index 0000000..51ab2b1
--- /dev/null
+++ b/libjava/java/util/Hashtable.java
@@ -0,0 +1,398 @@
+/* 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.util;
+
+import java.io.Serializable;
+
+/**
+ * @author Warren Levy <warrenl@cygnus.com>
+ * @date September 24, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct
+ */
+
+class HashtableEntry
+{
+ public Object key;
+ public Object value;
+ public HashtableEntry nextEntry = null;
+
+ public HashtableEntry(Object key, Object value)
+ {
+ this.key = key;
+ this.value = value;
+ }
+}
+
+class HashtableEnumeration implements Enumeration
+{
+ // TBD: Enumeration is not safe if new elements are put in the table as
+ // this could cause a rehash and we'd completely lose our place. Even
+ // without a rehash, it is undetermined if a new element added would
+ // appear in the enumeration. The spec says nothing about this, but
+ // the "Java Class Libraries" book infers that modifications to the
+ // hashtable during enumeration causes indeterminate results. Don't do it!
+ // A safer way would be to make a copy of the table (e.g. into a vector)
+ // but this is a fair bit more expensive.
+ private HashtableEntry[] bucket;
+ private int bucketIndex;
+ private HashtableEntry elem;
+ private int enumCount;
+ private int size;
+ private boolean values;
+
+ public HashtableEnumeration(HashtableEntry[] bkt, int sz, boolean isValues)
+ {
+ bucket = bkt;
+ bucketIndex = -1;
+ enumCount = 0;
+ elem = null;
+ size = sz;
+ values = isValues;
+ }
+
+ public boolean hasMoreElements()
+ {
+ return enumCount < size;
+ }
+
+ public Object nextElement()
+ {
+ if (!hasMoreElements())
+ throw new NoSuchElementException();
+
+ // Find next element
+ if (elem != null) // In the middle of a bucket
+ elem = elem.nextEntry;
+ while (elem == null) // Find the next non-empty bucket
+ elem = bucket[++bucketIndex];
+
+ enumCount++;
+ return values ? elem.value : elem.key;
+ }
+}
+
+// TBD: The algorithm used here closely reflects what is described in
+// the "Java Class Libraries" book. The "Java Language Spec" is much
+// less specific about the implementation. Because of this freedom
+// provided by the actual spec, hash table algorithms should be
+// investigated to see if there is a better alternative to this one.
+
+// TODO12:
+// public class Hashtable extends Dictionary
+// implements Map, Cloneable, Serializable
+
+public class Hashtable extends Dictionary implements Cloneable, Serializable
+{
+ private HashtableEntry bucket[];
+ private float loadFactor;
+ private int hsize = 0;
+
+ public Hashtable()
+ {
+ // The "Java Class Libraries" book (p. 919) says that initial size in this
+ // case is 101 (a prime number to increase the odds of even distribution).
+ this(101, 0.75F);
+ }
+
+ public Hashtable(int initialSize)
+ {
+ this(initialSize, 0.75F);
+ }
+
+ public Hashtable(int initialSize, float loadFactor)
+ {
+ if (initialSize < 0 || loadFactor <= 0.0 || loadFactor > 1.0)
+ throw new IllegalArgumentException();
+
+ bucket = new HashtableEntry[initialSize];
+ this.loadFactor = loadFactor;
+ }
+
+ // TODO12:
+ // public Hashtable(Map t)
+ // {
+ // }
+
+ public synchronized void clear()
+ {
+ // Aid the GC by nulling out the entries in the hash table.
+ for (int i = 0; i < bucket.length; i++)
+ {
+ HashtableEntry elem = bucket[i];
+ bucket[i] = null; // May already be null.
+ while (elem != null)
+ {
+ HashtableEntry next = elem.nextEntry;
+ elem.nextEntry = null; // May already be null.
+ elem = next;
+ }
+ }
+ hsize = 0;
+ }
+
+ public synchronized Object clone()
+ {
+ // New hashtable will have same initialCapacity and loadFactor.
+ Hashtable newTable = new Hashtable(bucket.length, loadFactor);
+
+ HashtableEntry newElem, prev = null;
+ for (int i = 0; i < bucket.length; i++)
+ for (HashtableEntry elem = bucket[i]; elem != null; elem = elem.nextEntry)
+ {
+ // An easy but expensive method is newTable.put(elem.key, elem.value);
+ // Since the hash tables are the same size, the buckets and collisions
+ // will be the same in the new one, so we can just clone directly.
+ // This is much cheaper than using put.
+ newElem = new HashtableEntry(elem.key, elem.value);
+ if (newTable.bucket[i] == null)
+ prev = newTable.bucket[i] = newElem;
+ else
+ prev = prev.nextEntry = newElem;
+ }
+
+ newTable.hsize = this.hsize;
+ return newTable;
+ }
+
+ public synchronized boolean contains(Object value) throws NullPointerException
+ {
+ // An exception is thrown here according to the JDK 1.2 doc.
+ if (value == null)
+ throw new NullPointerException();
+
+ for (int i = 0; i < bucket.length; i++)
+ for (HashtableEntry elem = bucket[i]; elem != null; elem = elem.nextEntry)
+ if (elem.value.equals(value))
+ return true;
+
+ return false;
+ }
+
+ public synchronized boolean containsKey(Object key)
+ {
+ // The Map interface mandates that we throw this.
+ if (key == null)
+ throw new NullPointerException ();
+
+ for (HashtableEntry elem = bucket[Math.abs(key.hashCode()
+ % bucket.length)];
+ elem != null; elem = elem.nextEntry)
+ if (elem.key.equals(key))
+ return true;
+
+ return false;
+ }
+
+ public synchronized Enumeration elements()
+ {
+ return new HashtableEnumeration(bucket, hsize, true);
+ }
+
+ public synchronized Object get(Object key)
+ {
+ // The Dictionary interface mandates that get() throw a
+ // NullPointerException if key is null.
+ if (key == null)
+ throw new NullPointerException ();
+
+ for (HashtableEntry elem = bucket[Math.abs (key.hashCode()
+ % bucket.length)];
+ elem != null; elem = elem.nextEntry)
+ if (elem.key.equals(key))
+ return elem.value;
+
+ return null;
+ }
+
+ public boolean isEmpty()
+ {
+ return this.hsize <= 0;
+ }
+
+ public synchronized Enumeration keys()
+ {
+ return new HashtableEnumeration(bucket, hsize, false);
+ }
+
+ public synchronized Object put(Object key, Object value)
+ throws NullPointerException
+ {
+ if (key == null || value == null)
+ throw new NullPointerException();
+
+ HashtableEntry prevElem = null;
+ final int index = Math.abs(key.hashCode() % bucket.length);
+
+ for (HashtableEntry elem = bucket[index]; elem != null;
+ prevElem = elem, elem = elem.nextEntry)
+ if (elem.key.equals(key))
+ {
+ // Update with the new value and then return the old one.
+ Object oldVal = elem.value;
+ elem.value = value;
+ return oldVal;
+ }
+
+ // At this point, we know we need to add a new element.
+ HashtableEntry newElem = new HashtableEntry(key, value);
+ if (bucket[index] == null)
+ bucket[index] = newElem;
+ else
+ prevElem.nextEntry = newElem;
+
+ if (++hsize > loadFactor * bucket.length)
+ rehash();
+
+ return null;
+ }
+
+ protected void rehash()
+ {
+ // Create a new table which is twice the size (plus one) of the old.
+ // One is added to make the new array length odd so it thus has at least
+ // a (small) possibility of being a prime number.
+ HashtableEntry oldBucket[] = bucket;
+ bucket = new HashtableEntry[bucket.length * 2 + 1];
+
+ // Copy over each entry into the new table
+ HashtableEntry elem;
+ for (int i = 0; i < oldBucket.length; i++)
+ for (elem = oldBucket[i]; elem != null; elem = elem.nextEntry)
+ {
+ // Calling put(elem.key, elem.value); would seem like the easy way
+ // but it is dangerous since put increases 'hsize' and calls rehash!
+ // This could become infinite recursion under the right
+ // circumstances. Instead, we'll add the element directly; this is a
+ // bit more efficient than put since the data is already verified.
+ final int index = Math.abs(elem.key.hashCode() % bucket.length);
+ HashtableEntry newElem = new HashtableEntry(elem.key, elem.value);
+ if (bucket[index] == null)
+ bucket[index] = newElem;
+ else
+ {
+ // Since this key can't already be in the table, just add this
+ // in at the top of the bucket.
+ newElem.nextEntry = bucket[index];
+ bucket[index] = newElem;
+ }
+ }
+ }
+
+ public synchronized Object remove(Object key)
+ {
+ // TBD: Hmm, none of the various docs say to throw an exception here.
+ if (key == null)
+ return null;
+
+ Object retval;
+ HashtableEntry prevElem = null;
+ final int index = Math.abs(key.hashCode() % bucket.length);
+
+ for (HashtableEntry elem = bucket[index]; elem != null;
+ prevElem = elem, elem = elem.nextEntry)
+ if (elem.key.equals(key))
+ {
+ retval = elem.value;
+ if (prevElem == null)
+ bucket[index] = elem.nextEntry;
+ else
+ prevElem.nextEntry = elem.nextEntry;
+ --hsize;
+ return retval;
+ }
+
+ return null;
+ }
+
+ public int size()
+ {
+ return this.hsize;
+ }
+
+ public synchronized String toString()
+ {
+ // Following the Java Lang Spec 21.5.4 (p. 636).
+
+ Enumeration keys = keys();
+ Enumeration values = elements();
+
+ // Prepend first element with open bracket
+ StringBuffer result = new StringBuffer("{");
+
+ // add first element if one exists
+ // TBD: Seems like it is more efficient to catch the exception than
+ // to call hasMoreElements each time around.
+ try
+ {
+ result.append(keys.nextElement().toString() + "=" +
+ values.nextElement().toString());
+ }
+ catch (NoSuchElementException ex)
+ {
+ }
+
+ // Prepend subsequent elements with ", "
+ try
+ {
+ while (true)
+ result.append(", " + keys.nextElement().toString() + "=" +
+ values.nextElement().toString());
+ }
+ catch (NoSuchElementException ex)
+ {
+ }
+
+ // Append last element with closing bracket
+ result.append("}");
+ return result.toString();
+ }
+
+ // TODO12:
+ // public Set entrySet()
+ // {
+ // }
+
+ // TODO12:
+ // public Set keySet()
+ // {
+ // }
+
+ // Since JDK 1.2:
+ // This method is identical to contains but is part of the 1.2 Map interface.
+ // TBD: Should contains return containsValue instead? Depends on which
+ // will be called more typically.
+ public synchronized boolean containsValue(Object value)
+ {
+ return this.contains(value);
+ }
+
+ // TODO12:
+ // public boolean equals(Object o)
+ // {
+ // }
+
+ // TODO12:
+ // public boolean hashCode()
+ // {
+ // }
+
+ // TODO12:
+ // public void putAll(Map t)
+ // {
+ // }
+
+ // TODO12:
+ // public Collection values()
+ // {
+ // }
+}
diff --git a/libjava/java/util/ListResourceBundle.java b/libjava/java/util/ListResourceBundle.java
new file mode 100644
index 0000000..a855c45
--- /dev/null
+++ b/libjava/java/util/ListResourceBundle.java
@@ -0,0 +1,52 @@
+/* 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.util;
+
+/**
+ * @author Anthony Green <green@cygnus.com>
+ * @date November 26, 1998.
+ */
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3,
+ * and "The Java Language Specification", ISBN 0-201-63451-1. */
+
+public abstract class ListResourceBundle extends ResourceBundle
+{
+ public final Object handleGetObject(String key)
+ {
+ Object a[][] = getContents();
+
+ for (int i = 0; i < a.length; i++)
+ {
+ if (key.compareTo((String) a[i][0]) == 0)
+ return a[i][1];
+ }
+ throw new MissingResourceException("can't find handle",
+ getClass().getName(),
+ key);
+ }
+
+ public Enumeration getKeys()
+ {
+ Object a[][] = getContents();
+
+ Vector keys = new Vector(a.length);
+
+ for (int i = 0; i < a.length; i++)
+ keys.addElement(a[i][0]);
+
+ return keys.elements();
+ }
+
+ protected abstract Object[][] getContents();
+
+ public ListResourceBundle()
+ {
+ }
+}
diff --git a/libjava/java/util/Locale.java b/libjava/java/util/Locale.java
new file mode 100644
index 0000000..e47cd1d
--- /dev/null
+++ b/libjava/java/util/Locale.java
@@ -0,0 +1,125 @@
+/* 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.util;
+
+/**
+ * @author Per Bothner <bothner@cygnus.com>
+ * @date October 24, 1998.
+ */
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3,
+ * and "The Java Language Specification", ISBN 0-201-63451-1.
+ * Status: None of the getDisplayXXX or getISO3XXX methods are implemented.
+ */
+public final class Locale implements java.io.Serializable, Cloneable
+{
+ // The fields are as specified in Sun's "Serialized Form"
+ // in the JDK 1.2 beta 4 API specification.
+ private String country;
+ private int hashcode;
+ private String language;
+ private String variant;
+ private static Locale defaultLocale;
+
+ // FIXME: many are still missing.
+ public static final Locale CANADA = new Locale ("en", "CA");
+ public static final Locale FRANCE = new Locale ("fr", "FR");
+ public static final Locale JAPAN = new Locale ("ja", "JP");
+ public static final Locale UK = new Locale ("en", "GB");
+ public static final Locale US = new Locale ("en", "US");
+
+ public Locale (String languageCode, String countryCode)
+ {
+ language = languageCode.toLowerCase();
+ country = countryCode.toUpperCase();
+ hashcode = languageCode.hashCode() ^ countryCode.hashCode();
+ }
+
+ public Locale (String languageCode, String countryCode,
+ String variantCode)
+ {
+ this (languageCode, countryCode);
+ variant = variantCode;
+ hashcode ^= variantCode.hashCode();
+ }
+
+ public Object clone ()
+ {
+ return (Object) new Locale (language, country, variant);
+ }
+
+ public boolean equals (Object obj)
+ {
+ if (! (obj instanceof Locale))
+ return false;
+ Locale loc = (Locale) obj;
+ if ((language == null && loc.language != null)
+ || (country == null && loc.country != null)
+ || (variant == null && loc.variant != null))
+ return false;
+ return (language.equals(loc.language)
+ && country.equals(loc.country)
+ && variant.equals(loc.variant));
+ }
+
+ public String getCountry ()
+ {
+ return country;
+ }
+
+ public String getLanguage ()
+ {
+ return language;
+ }
+
+ public String getVariant ()
+ {
+ return variant;
+ }
+
+ public int hashCode ()
+ {
+ return hashcode;
+ }
+
+ private static synchronized Locale setDefault()
+ {
+ if (defaultLocale != null)
+ return defaultLocale;
+ String language = System.getProperty("user.language");
+ String country = System.getProperty("user.region");
+ defaultLocale = new Locale (language == null ? "en" : language,
+ country == null ? "" : country);
+ return defaultLocale;
+ }
+
+ public static Locale getDefault ()
+ {
+ return defaultLocale == null ? setDefault() : defaultLocale;
+ }
+
+ public static void setDefault (Locale newLocale)
+ {
+ defaultLocale = newLocale;
+ }
+
+ public String toString ()
+ {
+ StringBuffer result = new StringBuffer(20);
+ result.append(language);
+ result.append('_');
+ result.append(country);
+ if (variant != null && variant.length() > 0)
+ {
+ result.append('_');
+ result.append(variant);
+ }
+ return result.toString();
+ }
+}
diff --git a/libjava/java/util/MissingResourceException.java b/libjava/java/util/MissingResourceException.java
new file mode 100644
index 0000000..e24cd6a
--- /dev/null
+++ b/libjava/java/util/MissingResourceException.java
@@ -0,0 +1,43 @@
+/* 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.util;
+
+/**
+ * @author Warren Levy <warrenl@cygnus.com>
+ * @date September 2, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ */
+
+public class MissingResourceException extends RuntimeException
+{
+ private String className;
+ private String key;
+
+ public MissingResourceException(String msg, String cName, String k)
+ {
+ super(msg);
+ className = cName;
+ key = k;
+ }
+
+ public String getClassName()
+ {
+ return className;
+ }
+
+ public String getKey()
+ {
+ return key;
+ }
+}
+
diff --git a/libjava/java/util/NoSuchElementException.java b/libjava/java/util/NoSuchElementException.java
new file mode 100644
index 0000000..2e6d024
--- /dev/null
+++ b/libjava/java/util/NoSuchElementException.java
@@ -0,0 +1,32 @@
+/* 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.util;
+
+/**
+ * @author Warren Levy <warrenl@cygnus.com>
+ * @date September 2, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ */
+
+public class NoSuchElementException extends RuntimeException
+{
+ public NoSuchElementException()
+ {
+ super();
+ }
+
+ public NoSuchElementException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/libjava/java/util/Observable.java b/libjava/java/util/Observable.java
new file mode 100644
index 0000000..627892e
--- /dev/null
+++ b/libjava/java/util/Observable.java
@@ -0,0 +1,98 @@
+/* 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.util;
+
+/**
+ * @author Warren Levy <warrenl@cygnus.com>
+ * @date September 2, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ */
+
+public class Observable
+{
+ /* tracks whether this object has changed */
+ private boolean changed;
+
+ /* list of the Observers registered as interested in this Observable */
+ private Vector observerVec;
+
+ /* TBD: This might be better implemented as an Observer[]
+ * but that would mean writing more code rather than making use of
+ * the existing Vector class (this also implies a larger text code
+ * space in resulting executables). The tradeoff is one of speed
+ * (manipulating the Observer[] directly) vs. size/reuse. In the future,
+ * we may decide to make the tradeoff and reimplement with an Observer[].
+ */
+
+ public Observable()
+ {
+ changed = false;
+ observerVec = new Vector();
+ }
+
+ public synchronized void addObserver(Observer obs)
+ {
+ // JDK 1.2 spec says not to add this if it is already there
+ if (!observerVec.contains(obs))
+ observerVec.addElement(obs);
+ }
+
+ protected synchronized void clearChanged()
+ {
+ changed = false;
+ }
+
+ public synchronized int countObservers()
+ {
+ return observerVec.size();
+ }
+
+ public synchronized void deleteObserver(Observer obs)
+ {
+ observerVec.removeElement(obs);
+ }
+
+ public synchronized void deleteObservers()
+ {
+ observerVec.removeAllElements();
+ }
+
+ public synchronized boolean hasChanged()
+ {
+ return changed;
+ }
+
+ public void notifyObservers()
+ {
+ notifyObservers(null);
+ }
+
+ public void notifyObservers(Object arg)
+ {
+ if (changed)
+ {
+ /* The JDK 1.2 spec states that though the order of notification
+ * is unspecified in subclasses, in Observable it is in the order
+ * of registration.
+ */
+ for (int i = 0, numObs = observerVec.size(); i < numObs; i++)
+ ((Observer) (observerVec.elementAt(i))).update(this, arg);
+ changed = false;
+ }
+ }
+
+ protected synchronized void setChanged()
+ {
+ changed = true;
+ }
+}
diff --git a/libjava/java/util/Observer.java b/libjava/java/util/Observer.java
new file mode 100644
index 0000000..c131f3b
--- /dev/null
+++ b/libjava/java/util/Observer.java
@@ -0,0 +1,24 @@
+/* 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.util;
+
+/**
+ * @author Warren Levy <warrenl@cygnus.com>
+ * @date August 25, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct
+ */
+
+public interface Observer
+{
+ public void update(Observable observed, Object arg);
+}
diff --git a/libjava/java/util/Properties.java b/libjava/java/util/Properties.java
new file mode 100644
index 0000000..aac7214
--- /dev/null
+++ b/libjava/java/util/Properties.java
@@ -0,0 +1,376 @@
+// Properties - Property list representation.
+
+/* 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.util;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.PushbackReader;
+
+/**
+ * @author Tom Tromey <tromey@cygnus.com>
+ * @date October 26, 1998.
+ */
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * Status: Complete to JDK 1.1.
+ */
+
+public class Properties extends Hashtable
+{
+ protected Properties defaults;
+
+ public String getProperty (String propName)
+ {
+ return getProperty (propName, null);
+ }
+
+ public String getProperty (String propName, String defVal)
+ {
+ String r = (String) get (propName);
+ if (r == null)
+ {
+ if (defaults != null)
+ r = defaults.getProperty(propName, defVal);
+ else
+ r = defVal;
+ }
+ return r;
+ }
+
+ public void list (PrintStream out)
+ {
+ Enumeration e = propertyNames ();
+ while (e.hasMoreElements())
+ {
+ String key = (String) e.nextElement();
+ String value = getProperty(key);
+ if (value != null)
+ {
+ if (value.length() > 40)
+ {
+ // JDK compatibility.
+ value = value.substring(0, 37) + "...";
+ }
+ out.print(key);
+ out.print("=");
+ out.println(value);
+ }
+ }
+ }
+
+ public void list (PrintWriter writer)
+ {
+ Enumeration e = propertyNames ();
+ while (e.hasMoreElements())
+ {
+ String key = (String) e.nextElement();
+ String value = getProperty(key);
+ if (value != null)
+ {
+ if (value.length() > 40)
+ {
+ // JDK compatibility.
+ value = value.substring(0, 37) + "...";
+ }
+ writer.print(key);
+ writer.print("=");
+ writer.println(value);
+ }
+ }
+ }
+
+ private final boolean skip_ws (PushbackReader reader) throws IOException
+ {
+ while (true)
+ {
+ int c = reader.read();
+ if (c == -1)
+ return false;
+ // FIXME: we use our own definition of whitespace.
+ // Character.isWhitespace includes newlines, which we don't
+ // want. Character.isSpaceChar doesn't include \t.
+ if (c == ' ' || c == '\t')
+ {
+ reader.unread(c);
+ return true;
+ }
+ }
+ }
+
+ // Note: this method needs to be rewritten for JDK 1.2.
+ // We rather arbitrarily decide that an EOF in the middle of a line
+ // means that the whole line should be ignored. The spec doesn't
+ // specifically address this, but this interpretation seems valid.
+ public synchronized void load (InputStream in) throws IOException
+ {
+ PushbackReader reader = new PushbackReader (new InputStreamReader (in));
+
+ StringBuffer key = new StringBuffer ();
+ StringBuffer value = new StringBuffer ();
+
+ nextLine:
+ while (true)
+ {
+ key.setLength(0);
+ value.setLength(0);
+
+ // Skip leading whitespace.
+ if (! skip_ws (reader))
+ return;
+
+ // Read key until key terminator.
+ boolean first_char = true;
+ int c;
+ while (true)
+ {
+ c = reader.read();
+ if (c == -1)
+ return;
+ if (c == '\\')
+ {
+ first_char = false;
+ c = reader.read();
+ if (c == -1)
+ return;
+ }
+
+ // If we found a comment, just read to end of line and
+ // then keep going.
+ if (first_char == true && (c == '#' || c == '!'))
+ {
+ while (c != -1 && c != '\r' && c != '\n')
+ c = reader.read();
+ if (c == -1)
+ return;
+ continue nextLine;
+ }
+
+ if (c == '\r' || c == '\n')
+ {
+ if (first_char)
+ continue nextLine;
+ reader.unread(c);
+ break;
+ }
+ // FIXME: again, our own definitino of whitespace.
+ if (c == ' ' || c == '\t' || c == ':' || c == '=')
+ break;
+
+ first_char = false;
+ key.append(c);
+ }
+
+ // Found end of key. Skip whitespace. If the terminator
+ // was whitespace, also skip a single instance of a "real"
+ // terminator, and then more whitespace.
+ if (! skip_ws (reader))
+ return;
+ if (c != ':' && c != '=')
+ {
+ c = reader.read();
+ if (c == -1)
+ return;
+ if (c == ':' || c == '=')
+ {
+ // Skip more whitespace.
+ if (! skip_ws (reader))
+ return;
+ }
+ else
+ reader.unread(c);
+ }
+
+ // Now read the value.
+ while (true)
+ {
+ c = reader.read();
+ if (c == -1)
+ return;
+ if (c == '\r' || c == '\n')
+ break;
+ if (c == '\\')
+ {
+ c = reader.read();
+ switch (c)
+ {
+ case -1:
+ return;
+ case 't':
+ c = '\t';
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case 'n':
+ c = '\n';
+ break;
+ case 'u':
+ c = 0;
+ for (int i = 0; i < 4; ++i)
+ {
+ int x = reader.read();
+ if (x == -1)
+ return;
+ int d = Character.digit((char) x, 16);
+ // FIXME: what to do here? We call it an
+ // error.
+ if (d == -1)
+ throw new IOException ();
+ c <<= 4;
+ c |= d;
+ }
+ break;
+ default:
+ // Nothing.
+ }
+ }
+ else
+ value.append(c);
+ }
+
+ put (key.toString(), value.toString());
+ }
+ }
+
+ public Properties ()
+ {
+ defaults = null;
+ }
+
+ public Properties (Properties defs)
+ {
+ defaults = defs;
+ }
+
+ private final void addHashEntries (Hashtable base)
+ {
+ if (defaults != null)
+ defaults.addHashEntries(base);
+ Enumeration keys = keys ();
+ while (keys.hasMoreElements())
+ base.put(keys.nextElement(), base);
+ }
+
+ public Enumeration propertyNames ()
+ {
+ // We make a new Hashtable that holds all the keys. Then we
+ // return an enumeration for this hash. We do this because we
+ // don't want modifications to be reflected in the enumeration
+ // (per JCL), and because there doesn't seem to be a
+ // particularly better way to ensure that duplicates are
+ // ignored.
+ Hashtable t = new Hashtable ();
+ addHashEntries (t);
+ return t.keys();
+ }
+
+ public synchronized void save (OutputStream out, String comment)
+ {
+ // Use a buffer because writing a single string through
+ // OutputStreamWriter is fairly expensive.
+ BufferedWriter output
+ = new BufferedWriter (new OutputStreamWriter (out));
+ String newline = System.getProperty("line.separator");
+
+ try
+ {
+ if (comment != null)
+ {
+ // FIXME: what if COMMENT contains newlines?
+ output.write("#");
+ output.write(comment);
+ output.write(newline);
+ }
+ output.write("# ");
+ output.write(new Date().toString());
+ output.write(newline);
+
+ Enumeration keys = keys ();
+ while (keys.hasMoreElements())
+ {
+ String key = (String) keys.nextElement();
+ String value = (String) get (key);
+
+ // FIXME: JCL says that the key can contain many Unicode
+ // characters. But it also doesn't say we should encode
+ // it in any way.
+ // FIXME: if key contains ':', '=', or whitespace, must
+ // quote it here.
+ output.write(key);
+ output.write("=");
+
+ boolean leading = true;
+ for (int i = 0; i < value.length(); ++i)
+ {
+ boolean new_lead = false;
+ char c = value.charAt(i);
+ switch (c)
+ {
+ case '\n':
+ output.write("\\n");
+ break;
+ case '\r':
+ output.write("\\r");
+ break;
+ case '\t':
+ output.write("\\t");
+ break;
+ case '\\':
+ output.write("\\\\");
+ break;
+
+ case '#':
+ case '!':
+ case '=':
+ case ':':
+ output.write("\\");
+ output.write(c);
+ break;
+
+ case ' ':
+ new_lead = leading;
+ if (leading)
+ output.write("\\");
+ output.write(c);
+ break;
+
+ default:
+ if (c < '\u0020' || c > '\u007e')
+ {
+ output.write("\\u");
+ output.write(Character.forDigit(c >>> 12, 16));
+ output.write(Character.forDigit((c >>> 8) & 0xff,
+ 16));
+ output.write(Character.forDigit((c >>> 4) & 0xff,
+ 16));
+ output.write(Character.forDigit(c & 0xff, 16));
+ }
+ else
+ output.write(c);
+ }
+ leading = new_lead;
+ }
+ output.write(newline);
+ }
+
+ output.flush();
+ }
+ catch (IOException ignore)
+ {
+ }
+ }
+}
diff --git a/libjava/java/util/Random.java b/libjava/java/util/Random.java
new file mode 100644
index 0000000..26010ce
--- /dev/null
+++ b/libjava/java/util/Random.java
@@ -0,0 +1,148 @@
+/* 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.util;
+
+import java.io.Serializable;
+
+/**
+ * @author Warren Levy <warrenl@cygnus.com>
+ * @date August 25, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct
+ */
+
+/* This class is completely specified by the spec to ensure absolute
+ * portability between all implementations of Java
+ */
+public class Random implements Serializable
+{
+ /* Used by next() to hold the state of the pseudorandom number generator */
+ protected long seed;
+
+ /* Used by nextGaussian() to hold a precomputed value */
+ /* to be delivered by that method the next time it is called */
+ protected double nextNextGaussian;
+
+ /* Used by nextGaussian() to keep track of whether it is has precomputed */
+ /* and stashed away the next value to be delivered by that method */
+ protected boolean haveNextNextGaussian = false;
+
+ public Random()
+ {
+ this(System.currentTimeMillis());
+ }
+
+ public Random(long seed)
+ {
+ setSeed(seed);
+ }
+
+ protected synchronized int next(int bits)
+ {
+ seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1);
+ return (int)(seed >>> (48 - bits));
+ }
+
+ // JDK1.2
+ public boolean nextBoolean()
+ {
+ return next(1) != 0;
+ }
+
+ /* The method nextBytes() is not fully specified in the published specs.
+ * At first I implemented it simply via:
+ * for (int i = 0; i < buf.length; i++)
+ * buf[i] = (byte)next(8);
+ * but a simple test did not yield the same results as the std implementation.
+ * There seemed to be a relationship where each i byte above was at pos 4*i+3
+ * in the std. For efficiency, by reducing calls to the expensive math
+ * routines, the std probably was calling next(32) once rather than next(8)
+ * 4 times. Changing the algorithm to the one below based on that assumption
+ * then yielded identical results to the std.
+ */
+ public void nextBytes(byte[] buf)
+ {
+ int randInt = 0;
+
+ for (int i = 0; i < buf.length; i++)
+ {
+ int shift = (i % 4) * 8;
+ if (shift == 0)
+ randInt = next(32);
+ buf[i] = (byte) (randInt >> shift);
+ }
+ }
+
+ public double nextDouble()
+ {
+ return (((long)next(26) << 27) + next(27)) / (double)(1L << 53);
+ }
+
+ public float nextFloat()
+ {
+ return next(24) / ((float)(1 << 24));
+ }
+
+ public synchronized double nextGaussian()
+ {
+ if (haveNextNextGaussian)
+ {
+ haveNextNextGaussian = false;
+ return nextNextGaussian;
+ }
+ else
+ {
+ double v1, v2, s;
+ do
+ {
+ v1 = 2 * nextDouble() - 1; // between -1.0 and 1.0
+ v2 = 2 * nextDouble() - 1; // between -1.0 and 1.0
+ s = v1 * v1 + v2 * v2;
+ } while (s >= 1);
+ double norm = Math.sqrt(-2 * Math.log(s)/s);
+ nextNextGaussian = v2 * norm;
+ haveNextNextGaussian = true;
+ return v1 * norm;
+ }
+ }
+
+ public int nextInt()
+ {
+ return next(32);
+ }
+
+ // JDK1.2
+ public int nextInt(int n)
+ {
+ if (n <= 0)
+ throw new IllegalArgumentException("n must be positive");
+
+ int bits, val;
+ do
+ {
+ bits = next(31);
+ val = bits % n;
+ } while (bits - val + (n-1) < 0);
+ return val;
+ }
+
+ public long nextLong()
+ {
+ return ((long)next(32) << 32) + next(32);
+ }
+
+ public synchronized void setSeed(long seed)
+ {
+ this.seed = (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1);
+ haveNextNextGaussian = false;
+ }
+}
diff --git a/libjava/java/util/ResourceBundle.java b/libjava/java/util/ResourceBundle.java
new file mode 100644
index 0000000..ba1d3f9
--- /dev/null
+++ b/libjava/java/util/ResourceBundle.java
@@ -0,0 +1,188 @@
+/* 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.util;
+
+/**
+ * @author Anthony Green <green@cygnus.com>
+ * @date November 26, 1998.
+ */
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3,
+ * and "The Java Language Specification", ISBN 0-201-63451-1. */
+
+public abstract class ResourceBundle
+{
+ protected ResourceBundle parent;
+
+ public ResourceBundle ()
+ {
+ }
+
+ public final String getString (String key) throws MissingResourceException
+ {
+ return (String) getObject(key);
+ }
+
+ public final String[] getStringArray (String key)
+ throws MissingResourceException
+ {
+ return (String[]) getObject(key);
+ }
+
+ public final Object getObject(String key) throws MissingResourceException
+ {
+ Object result;
+
+ try
+ {
+ return handleGetObject (key);
+ }
+ catch (MissingResourceException ex)
+ {
+ if (parent != null)
+ return parent.getObject(key);
+ else
+ throw ex;
+ }
+ }
+
+ public static final ResourceBundle getBundle(String baseName)
+ throws MissingResourceException
+ {
+ return getBundle(baseName, Locale.getDefault());
+ }
+
+ // Start searching with the name bundleName. Continue searching by
+ // stripping off the '_' delimited tails until the search name is
+ // the same as stopHere.
+ private static final ResourceBundle trySomeGetBundle (String bundleName,
+ String stopHere)
+ {
+ Class rbc;
+
+ while (true)
+ {
+ try
+ {
+ rbc = Class.forName(bundleName);
+ try
+ {
+ return (ResourceBundle) rbc.newInstance();
+ }
+ catch (IllegalAccessException ex)
+ {
+ // Fall through
+ }
+ catch (InstantiationException ex)
+ {
+ // Fall through
+ }
+ return null;
+ }
+ catch (ClassNotFoundException ex)
+ {
+ if (bundleName.compareTo(stopHere) == 0)
+ return null;
+ else
+ {
+ int last = bundleName.lastIndexOf('_');
+
+ // No more underscores?
+ if (last == -1)
+ return null;
+
+ // Loop around, testing this new shorter name.
+ bundleName = bundleName.substring(0, last);
+ }
+ }
+ }
+ }
+
+ // Search for bundles, but stop at baseName_language.
+ private static final ResourceBundle partialGetBundle (String baseName,
+ Locale locale)
+ {
+ ResourceBundle rb;
+
+ String bundleName = (baseName
+ + "_"
+ + locale.getLanguage() + "_"
+ + locale.getCountry() + "_"
+ + locale.getVariant());
+
+ String stopHere = (baseName
+ + "_"
+ + locale.getLanguage());
+
+
+ rb = trySomeGetBundle(bundleName, stopHere);
+
+ return rb;
+ }
+
+ public static final ResourceBundle getBundle (String baseName,
+ Locale locale)
+ throws MissingResourceException
+ {
+ ResourceBundle rb;
+ Class rbc;
+
+ // FIXME: We can't currently rely on NullPointerException being
+ // thrown when we invoke a method on a null object.
+ if (locale == null)
+ throw new NullPointerException ();
+
+ rb = partialGetBundle(baseName, locale);
+ if (rb != null)
+ return rb;
+
+ if (! locale.equals(Locale.getDefault()))
+ {
+ rb = partialGetBundle(baseName, Locale.getDefault());
+ if (rb != null)
+ return rb;
+ }
+
+ // Try just the baseName.
+ try
+ {
+ rbc = Class.forName (baseName);
+ try
+ {
+ return (ResourceBundle) rbc.newInstance();
+ }
+ catch (IllegalAccessException ex)
+ {
+ // Fall through.
+ }
+ catch (InstantiationException ex)
+ {
+ // Fall through.
+ }
+ }
+ catch (ClassNotFoundException ex)
+ {
+ // Fall through.
+ }
+
+ throw new MissingResourceException("can't load bundle",
+ baseName,
+ "bundle");
+ }
+
+ protected void setParent(ResourceBundle parent)
+ {
+ this.parent = parent;
+ }
+
+ protected abstract Object handleGetObject(String key)
+ throws MissingResourceException;
+
+ public abstract Enumeration getKeys();
+}
diff --git a/libjava/java/util/SimpleTimeZone.java b/libjava/java/util/SimpleTimeZone.java
new file mode 100644
index 0000000..6082b18
--- /dev/null
+++ b/libjava/java/util/SimpleTimeZone.java
@@ -0,0 +1,182 @@
+/* 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.util;
+
+/**
+ * @author Per Bothner <bothner@cygnus.com>
+ * @date October 24, 1998.
+ */
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3.
+ * Status: Does not know how to figure out if daylight savings time
+ * is in effect; hence only correct for zones without DST.
+ * No known spec for hashCode.
+ */
+
+public class SimpleTimeZone extends TimeZone
+{
+ // The fields are as specified in Sun's "Serialized Form"
+ // in the JDK 1.2 beta 4 API specification.
+
+ int dstSavings = 60 * 60 * 1000;
+
+ int rawOffset;
+
+ // int serialVersionOnStream;
+
+ int startDay;
+ int startDayOfWeek;
+ int startMode; /// Seems to be JDK 1.2 only.
+
+ int startMonth;
+
+ int startTime;
+
+ int startYear;
+
+ int endDay;
+
+ int endDayOfWeek;
+
+ int endMode; // Seems to be JDK 1.2 only.
+
+ int endMonth;
+
+ int endTime;
+
+ // byte[] monthLength;
+
+ boolean useDaylight;
+
+ public SimpleTimeZone (int rawOffset, String ID)
+ {
+ setID(ID);
+ this.rawOffset = rawOffset;
+ }
+
+ public SimpleTimeZone (int rawOffset, String ID,
+ int startMonth, int startDay,
+ int startDayOfWeek, int startTime,
+ int endMonth, int endDay,
+ int endDayOfWeek, int endTime)
+ {
+ this(rawOffset, ID);
+ setStartRule (startMonth, startDay, startDayOfWeek, startTime);
+ setEndRule (endMonth, endDay, endDayOfWeek, endTime);
+ }
+
+ public int getRawOffset() { return rawOffset; }
+ public void setRawOffset (int offsetMillis) { rawOffset = offsetMillis; }
+
+ public int getOffset (int era, int year, int month, int day,
+ int dayOfWeek, int millis)
+ {
+ int offset = getRawOffset();
+ if (useDaylight)
+ {
+ if (startYear != 0
+ && (year < startYear || era == GregorianCalendar.BC))
+ return offset;
+ boolean midYearSummer = startMonth < endMonth;
+ if (midYearSummer ? (month < startMonth || month > endMonth)
+ : (month < startMonth && month > endMonth))
+ return offset; // Definitely not DST.
+ if (midYearSummer ? (month > startMonth && month < endMonth)
+ : (month > startMonth || month < endMonth))
+ return offset + dstSavings; // Definitely DST.
+ // Now it gets more complicated. Bail for now.
+ throw new Error("not implemented - SimpleTimeZone.getOffset");
+ }
+ return offset;
+ }
+
+ public boolean useDaylightTime() { return useDaylight; }
+
+ public boolean inDaylightTime(Date date)
+ {
+ if (! useDaylight)
+ return false;
+ throw new Error("not implemented - SimpleTimeZone.inDaylightTime");
+ }
+
+ public int getDSTSavings () { return dstSavings; }
+
+ public void setDSTSavings (int millisSavedDuringDST)
+ { dstSavings = millisSavedDuringDST; }
+
+ public void setStartRule (int month, int dayOfWeekInMonth,
+ int dayOfWeek, int time)
+ {
+ this.startMonth = month;
+ this.startDay = dayOfWeekInMonth;
+ this.startDayOfWeek = dayOfWeek;
+ this.startTime = time;
+ this.useDaylight = true;
+ }
+
+ public void setEndRule (int month, int dayOfWeekInMonth,
+ int dayOfWeek, int time)
+ {
+ this.endMonth = month;
+ this.endDay = dayOfWeekInMonth;
+ this.endDayOfWeek = dayOfWeek;
+ this.endTime = time;
+ this.useDaylight = true;
+ }
+
+ public void setStartYear (int year)
+ {
+ this.startYear = startYear;
+ }
+
+ public boolean hasSameRules (TimeZone other)
+ {
+ if (this == other)
+ return true;
+ if (! (other instanceof SimpleTimeZone))
+ return false;
+ SimpleTimeZone o = (SimpleTimeZone) other;
+ if (rawOffset != o.rawOffset)
+ return false;
+ if (useDaylight != o.useDaylight)
+ return false;
+ if (! useDaylight)
+ return true;
+ return startDay == o.startDay
+ && startDayOfWeek == o.startDayOfWeek
+ && startMonth == o.startMonth
+ && startTime == o.startTime
+ && endDay == o.endDay
+ && endDayOfWeek == o.endDayOfWeek
+ && endMonth == o.endMonth
+ && endTime == o.endTime
+ && startYear == o.startYear
+ && startMode == o.startMode
+ && endMode == o.endMode;
+ }
+
+ public boolean equals (Object obj)
+ {
+ if (! (obj instanceof SimpleTimeZone))
+ return false;
+ SimpleTimeZone other = (SimpleTimeZone) obj;
+ return getID() == other.getID() && hasSameRules(other);
+ }
+
+ public int hashCode ()
+ {
+ // FIXME - this does not folow any spec (since none is public)!
+ int hash = rawOffset;
+ if (useDaylight)
+ hash += dstSavings + startYear + startMode + endMode
+ + startDay + startDayOfWeek + startMonth + startTime
+ + endDay + endDayOfWeek + endMonth + endTime;
+ return hash;
+ }
+}
diff --git a/libjava/java/util/Stack.java b/libjava/java/util/Stack.java
new file mode 100644
index 0000000..bc45888
--- /dev/null
+++ b/libjava/java/util/Stack.java
@@ -0,0 +1,74 @@
+/* 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.util;
+
+/**
+ * @author Warren Levy <warrenl@cygnus.com>
+ * @date August 20, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct
+ */
+
+public class Stack extends Vector
+{
+ // Could use Vector methods internally for the following methods
+ // but have used Vector fields directly for efficiency (i.e. this
+ // often reduces out duplicate bounds checking).
+
+ public boolean empty()
+ {
+ return elementCount == 0;
+ }
+
+ public synchronized Object peek()
+ {
+ if (elementCount == 0)
+ throw new EmptyStackException();
+
+ return elementData[elementCount - 1];
+ }
+
+ public synchronized Object pop()
+ {
+ if (elementCount == 0)
+ throw new EmptyStackException();
+
+ Object obj = elementData[--elementCount];
+
+ // Set topmost element to null to assist the gc in cleanup
+ elementData[elementCount] = null;
+ return obj;
+ }
+
+ public Object push(Object obj)
+ {
+ // When growing the Stack, use the Vector routines in case more
+ // memory is needed.
+ // Note: spec indicates that this method *always* returns obj passed in!
+
+ addElement(obj);
+ return obj;
+ }
+
+ public synchronized int search(Object obj)
+ {
+ // Return the position of obj on the stack as measured from the top;
+ // i.e. the top element is 1, the next element down is 2, etc.
+ // If obj is not on the stack, return -1
+
+ for (int i = elementCount-1; i >=0; --i)
+ if (elementData[i].equals(obj))
+ return elementCount - i;
+
+ return -1;
+ }
+}
diff --git a/libjava/java/util/StringTokenizer.java b/libjava/java/util/StringTokenizer.java
new file mode 100644
index 0000000..4516057
--- /dev/null
+++ b/libjava/java/util/StringTokenizer.java
@@ -0,0 +1,185 @@
+/* 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.util;
+
+/**
+ * @author Warren Levy <warrenl@cygnus.com>
+ * @date August 24, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct
+ */
+
+public class StringTokenizer implements Enumeration
+{
+ /* String to be parsed */
+ private String inputString;
+
+ /* String to be parsed put into a char array for efficient access */
+ private char[] chArray;
+
+ /* Set of delimiter characters for separating tokens */
+ private String delimiters;
+
+ /* Whether delimiters in this instance are treated as tokens themselves */
+ private boolean returnDelimiters;
+
+ /* Index into the input string to start parsing for the next token */
+ private int inputStringIndex;
+
+ public StringTokenizer(String str)
+ {
+ this(str, " \t\n\r", false);
+ }
+
+ public StringTokenizer(String str, String delims)
+ {
+ this(str, delims, false);
+ }
+
+ public StringTokenizer(String str, String delims, boolean retDelim)
+ {
+ inputString = str;
+ delimiters = delims;
+ returnDelimiters = retDelim;
+ inputStringIndex = 0;
+
+ // Work on a copy of the remaining string in a char array
+ // to gain efficiency of using primitives
+ chArray = new char[inputString.length()];
+ inputString.getChars(0, inputString.length(), chArray, 0);
+ }
+
+ public int countTokens()
+ {
+ int count = 0;
+ int delimiterCount = 0;
+ boolean tokenFound = false; // Set when a non-delimiter is found
+ int offset = inputStringIndex;
+
+ // Note for efficiency, we count up the delimiters rather than check
+ // returnDelimiters every time we encounter one. That way, we can
+ // just do the conditional once at the end of the method
+ while (offset < chArray.length)
+ {
+ if (isDelimiter(chArray[offset++]))
+ {
+ if (tokenFound)
+ {
+ // Got to the end of a token
+ count++;
+ tokenFound = false;
+ }
+
+ delimiterCount++; // Increment for this delimiter
+ }
+ else
+ {
+ tokenFound = true;
+
+ // Get to the end of the token
+ while (offset < chArray.length && !isDelimiter(chArray[offset]))
+ offset++;
+ }
+ }
+
+ // Make sure to count the last token
+ if (tokenFound)
+ count++;
+
+ // if counting delmiters add them into the token count
+ return returnDelimiters ? count + delimiterCount : count;
+ }
+
+ public boolean hasMoreElements()
+ {
+ return hasMoreTokens();
+ }
+
+ public boolean hasMoreTokens()
+ {
+ int offset = inputStringIndex;
+
+ while (offset < chArray.length)
+ if (!isDelimiter(chArray[offset++]) || returnDelimiters)
+ {
+ // update the current position with the start of the next token
+ inputStringIndex = --offset;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public Object nextElement()
+ {
+ return nextToken();
+ }
+
+ public String nextToken()
+ {
+ int offset = inputStringIndex;
+ int startSubstr = -1;
+
+ // Make sure we have more chars left to parse
+ // and then find the start of the next token
+ while (offset < chArray.length && startSubstr < 0)
+ {
+ // Find the start of the token; skipping initial delimiters
+ if (!isDelimiter(chArray[offset++]))
+ startSubstr = offset - 1;
+ else if (returnDelimiters)
+ {
+ // The single char delimiter is treated as a token
+ inputStringIndex = offset; // update the current position
+
+ return inputString.substring(offset - 1, inputStringIndex);
+ }
+ }
+
+ // Now look for the end of the token
+ while (offset < chArray.length)
+ {
+ if (isDelimiter(chArray[offset++]))
+ {
+ // Found the end of token
+ inputStringIndex = offset - 1; // update the current position
+
+ return inputString.substring(startSubstr, inputStringIndex);
+ }
+ }
+
+ // Got to the end of the string without finding the start of a token
+ if (startSubstr < 0)
+ throw new NoSuchElementException();
+
+ // Got to the end of the string before a delimiter
+ inputStringIndex = offset; // update the current position
+
+ return inputString.substring(startSubstr, inputStringIndex);
+ }
+
+ public String nextToken(String delims)
+ {
+ // First replace with new set of delimiters
+ delimiters = delims;
+
+ return nextToken();
+ }
+
+ // This private method could be inlined but the other methods are
+ // more readable this way, so we'll take the hit on efficiency.
+ private boolean isDelimiter(char ch)
+ {
+ return delimiters.indexOf(ch) >= 0;
+ }
+}
diff --git a/libjava/java/util/TimeZone.java b/libjava/java/util/TimeZone.java
new file mode 100644
index 0000000..ad2dd62
--- /dev/null
+++ b/libjava/java/util/TimeZone.java
@@ -0,0 +1,120 @@
+/* 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.util;
+
+/**
+ * @author Per Bothner <bothner@cygnus.com>
+ * @date October 24, 1998.
+ */
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3.
+ * Status: getAvailableIDs, getDefault, getTimeZone only know about GMT.
+ */
+
+public abstract class TimeZone implements java.io.Serializable, Cloneable
+{
+ public static final int SHORT = 0;
+ public static final int LONG = 1;
+
+ // The fields are as specified in Sun's "Serialized Form"
+ // in the JDK 1.2 beta 4 API specification.
+ String ID;
+
+ static final TimeZone zoneGMT = new SimpleTimeZone(0, "GMT");
+
+ private static TimeZone zoneDefault;
+
+ public TimeZone ()
+ {
+ }
+
+ public abstract int getOffset (int era, int year, int month,
+ int day, int dayOfWeek, int milliseconds);
+
+ public abstract void setRawOffset (int offsetMillis);
+
+ public abstract int getRawOffset ();
+
+ public String getID () { return ID; }
+
+ public void setID (String ID) { this.ID = ID; }
+
+ public final String getDisplayName()
+ {
+ return ID; // FIXME
+ }
+
+ // public final String getDisplayName (Local locale) { ... } FIXME
+
+ public final String getDisplayName (boolean daylight, int style)
+ {
+ return ID; // FIXME
+ }
+
+ /*
+ public final String getDisplayName (boolean daylight, int style, Locale locale)
+ {
+ return ID; // FIXME
+ }
+ */
+
+ public abstract boolean useDaylightTime();
+
+ public abstract boolean inDaylightTime (Date date);
+
+ public static TimeZone getTimeZone (String ID)
+ {
+ return zoneGMT; // FIXME
+ }
+
+ public static String[] getAvailableIDs()
+ { // FIXME - only knows about GMT
+ String[] zones = new String[1];
+ zones[0] = "GMT";
+ return zones;
+ }
+
+ public static String[] getAvailableIDs(int rawOffset)
+ {
+ return rawOffset == 0 ? getAvailableIDs() : new String[0]; // FIXME
+ }
+
+ private static synchronized TimeZone setDefault()
+ {
+ if (zoneDefault == null)
+ {
+ try
+ {
+ String id = System.getProperty("user.timezone");
+ if (id != null && ! id.equals("GMT"))
+ zoneDefault = getTimeZone(id);
+ }
+ catch (Exception ex)
+ {
+ }
+ if (zoneDefault == null)
+ zoneDefault = zoneGMT;
+ }
+ return zoneDefault;
+ }
+
+ public static TimeZone getDefault()
+ {
+ return zoneDefault == null ? setDefault() : zoneDefault;
+ }
+
+ public static void setDefault (TimeZone zone) { zoneDefault = zone; }
+
+ public boolean hasSameRules (TimeZone other)
+ {
+ return this == other;
+ }
+
+ // public Object clone ();
+}
diff --git a/libjava/java/util/TooManyListenersException.java b/libjava/java/util/TooManyListenersException.java
new file mode 100644
index 0000000..13bbc4e
--- /dev/null
+++ b/libjava/java/util/TooManyListenersException.java
@@ -0,0 +1,32 @@
+/* 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.util;
+
+/**
+ * @author Warren Levy <warrenl@cygnus.com>
+ * @date September 2, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ */
+
+public class TooManyListenersException extends Exception
+{
+ public TooManyListenersException()
+ {
+ super();
+ }
+
+ public TooManyListenersException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/libjava/java/util/Vector.java b/libjava/java/util/Vector.java
new file mode 100644
index 0000000..aaa9ea2
--- /dev/null
+++ b/libjava/java/util/Vector.java
@@ -0,0 +1,450 @@
+/* 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.util;
+
+import java.io.Serializable;
+
+/**
+ * @author Warren Levy <warrenl@cygnus.com>
+ * @date August 17, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct
+ */
+
+class VectorEnumeration implements Enumeration
+{
+ private int enumIndex;
+ private Vector enumVec;
+
+ public VectorEnumeration(Vector vec)
+ {
+ enumVec = vec;
+ enumIndex = 0;
+ }
+
+ public boolean hasMoreElements()
+ {
+ return enumIndex < enumVec.size();
+ }
+
+ public Object nextElement()
+ {
+ if (!hasMoreElements())
+ throw new NoSuchElementException();
+
+ return enumVec.elementData[enumIndex++];
+ }
+}
+
+// TODO12:
+// public class Vector extends AbstractList
+// implements List, Cloneable, Serializable
+
+public class Vector implements Cloneable, Serializable
+{
+ /* The size of the increment to use when growing this vector.
+ The default of 0 means to double the capacity when growing. */
+ protected int capacityIncrement;
+
+ /* The number of elements currently in elementData */
+ protected int elementCount;
+
+ /* The buffer in which elements of this vector are stored */
+ protected Object[] elementData;
+
+ public Vector()
+ {
+ this(10, 0);
+ }
+
+ public Vector(int initCap)
+ {
+ this(initCap, 0);
+ }
+
+ public Vector(int initCap, int capIncrement)
+ {
+ if (initCap < 0)
+ throw new IllegalArgumentException ();
+ elementData = new Object[initCap];
+ capacityIncrement = capIncrement;
+ elementCount = 0;
+ }
+
+ public final synchronized void addElement(Object obj)
+ {
+ // Make sure there's room for a new element
+ if (elementCount == elementData.length)
+ ensureCapacity(elementCount+1);
+
+ elementData[elementCount++] = obj;
+ }
+
+ public final int capacity()
+ {
+ return elementData.length;
+ }
+
+ public synchronized Object clone()
+ {
+ // New vector needs to have same size, capacity and capacityIncrement
+ Vector newVec = new Vector(elementData.length, capacityIncrement);
+
+ System.arraycopy(elementData, 0, newVec.elementData, 0, elementCount);
+ newVec.elementCount = elementCount;
+ return newVec;
+ }
+
+ public final boolean contains(Object obj)
+ {
+ for (int i = 0; i < elementCount; i++)
+ {
+ if (obj == null
+ ? elementData[i] == null
+ : obj.equals(elementData[i]))
+ return true;
+ }
+
+ return false;
+ }
+
+ public final synchronized void copyInto(Object[] objArray)
+ {
+ System.arraycopy(elementData, 0, objArray, 0, elementCount);
+ }
+
+ public final synchronized Object elementAt(int idx)
+ {
+ if (idx < 0 || idx >= size())
+ throw new ArrayIndexOutOfBoundsException();
+
+ return elementData[idx];
+ }
+
+ public final synchronized Enumeration elements()
+ {
+ return new VectorEnumeration(this);
+ }
+
+ public final synchronized void ensureCapacity(int minCap)
+ {
+ // Increasing the vector could make it much larger than minCap;
+ // e.g. if minCap is just larger than the vector, size may double.
+ // If someone cares about this possibility they should set capacityIncrement
+ if (minCap > elementData.length)
+ {
+ // Increase the vector; double it if capacityIncrement is zero
+ int newSize = elementData.length;
+ newSize +=
+ (capacityIncrement > 0) ? capacityIncrement : elementData.length;
+
+ // Make sure newSize is at least minCap
+ if (newSize < minCap)
+ newSize = minCap;
+
+ Object[] newArray = new Object[newSize];
+ System.arraycopy(elementData, 0, newArray, 0, elementCount);
+ elementData = newArray;
+ }
+ }
+
+ public final synchronized Object firstElement()
+ {
+ if (elementCount == 0)
+ throw new NoSuchElementException();
+
+ return elementData[0];
+ }
+
+ public final int indexOf(Object obj)
+ {
+ return indexOf(obj, 0);
+ }
+
+ public final synchronized int indexOf(Object obj, int idx)
+ {
+ if (idx < 0)
+ throw new IllegalArgumentException ();
+ for (int i = idx; i < elementCount; i++)
+ {
+ if (obj == null
+ ? elementData[i] == null
+ : obj.equals(elementData[i]))
+ return i;
+ }
+
+ return -1;
+ }
+
+ public final synchronized void insertElementAt(Object obj, int idx)
+ {
+ if (idx < 0 || idx > size())
+ throw new ArrayIndexOutOfBoundsException();
+ else if (idx == size()) // Spec says just use addElement()
+ addElement(obj);
+ else
+ {
+ // Make sure there's room for a new element
+ if (elementCount == elementData.length)
+ ensureCapacity(elementCount+1);
+
+ // Shift the existing elements up and increment elementCount
+ for (int i = elementCount++; i > idx; --i)
+ elementData[i] = elementData[i-1];
+
+ elementData[idx] = obj;
+ }
+ }
+
+ public final boolean isEmpty()
+ {
+ return elementCount == 0;
+ }
+
+ public final synchronized Object lastElement()
+ {
+ if (elementCount == 0)
+ throw new NoSuchElementException();
+
+ return elementData[elementCount - 1];
+ }
+
+ public final int lastIndexOf(Object obj)
+ {
+ return lastIndexOf(obj, size()-1);
+ }
+
+ public final synchronized int lastIndexOf(Object obj, int idx)
+ {
+ if (idx < 0)
+ throw new IllegalArgumentException ();
+ for (int i = idx; i >= 0; --i)
+ {
+ if (obj == null
+ ? elementData[i] == null
+ : obj.equals(elementData[i]))
+ return i;
+ }
+
+ return -1;
+ }
+
+ public final synchronized void removeAllElements()
+ {
+ // Remove elements now to assist the gc in early cleanup
+ for (int i = elementCount-1; i >= 0; --i)
+ elementData[i] = null;
+ elementCount = 0;
+ }
+
+ public final synchronized boolean removeElement(Object obj)
+ {
+ for (int i = 0; i < elementCount; i++)
+ {
+ if (obj == null
+ ? elementData[i] == null
+ : obj.equals(elementData[i]))
+ {
+ int j;
+
+ // Decrement count first to ensure we don't walk off end of array
+ --elementCount;
+
+ for (j = i; j < elementCount; j++)
+ elementData[j] = elementData[j+1];
+
+ // At this point, j was incrememented and points to old last element
+ // Remove element now to assist the gc in early cleanup
+ elementData[j] = null;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public final synchronized void removeElementAt(int idx)
+ {
+ int i;
+
+ if (idx < 0 || idx >= size())
+ throw new ArrayIndexOutOfBoundsException();
+
+ // Decrement count first to ensure we don't walk off the end of the array
+ --elementCount;
+
+ for (i = idx; i < elementCount; i++)
+ elementData[i] = elementData[i+1];
+
+ // At this point, i was incrememented and now points to the old last element
+ // Remove element now to assist the gc in early cleanup
+ elementData[i] = null;
+ }
+
+ public final synchronized void setElementAt(Object obj, int idx)
+ {
+ if (idx < 0 || idx >= size())
+ throw new ArrayIndexOutOfBoundsException();
+
+ elementData[idx] = obj;
+ }
+
+ public final synchronized void setSize(int newSize)
+ {
+ if (newSize < 0)
+ throw new ArrayIndexOutOfBoundsException();
+
+ // Java Lang Spec p. 658 says to remove the excess elements and discard
+ // when new size is smaller than old size.
+ // When truncating, we could alternatively just reset elementCount instead
+ // of freeing up the memory if the spec hadn't specified. The spec makes
+ // sense though; if someone cares enough to call a setSize() function
+ // they probably are doing so to free memory.
+ if (newSize < elementCount)
+ {
+ elementCount = newSize;
+ trimToSize();
+ }
+ else if (newSize > elementCount) // Skip == case
+ {
+ // TBD: ensureCapacity() may create a vector much larger than newSize;
+ // do we want to make the vector exactly newSize? Spec is unclear.
+ ensureCapacity(newSize);
+
+ // Make sure to null out new elements of grown vector
+ for (int i = elementCount; i < newSize; i++)
+ elementData[i] = null;
+ elementCount = newSize;
+ }
+ }
+
+ public final int size()
+ {
+ return elementCount;
+ }
+
+ public final synchronized String toString()
+ {
+ // Following the Java Lang Spec p. 656
+
+ // Prepend first element with open bracket
+ StringBuffer result = new StringBuffer("[");
+
+ if (elementCount > 0) // add first element if one exists
+ result.append(elementData[0].toString());
+
+ // Prepend subsequent elements with ", "
+ for (int i = 1; i < elementCount; i++)
+ result.append(", ").append(elementData[i].toString());
+
+ // Append last element with closing bracket
+ result.append("]");
+ return result.toString();
+ }
+
+ public final synchronized void trimToSize()
+ {
+ // Give up excess storage capacity to save memory
+ //
+ // Don't bother checking for the case where size() == the capacity of the
+ // vector since that is a much less likely case; it's more efficient to
+ // not do the check and lose a bit of performance in that infrequent case
+ Object[] newArray = new Object[elementCount];
+ System.arraycopy(elementData, 0, newArray, 0, elementCount);
+ elementData = newArray;
+ }
+
+ // TODO12:
+ // public Vector(Collection c)
+ // {
+ // }
+
+ // TODO12:
+ // public public boolean add(Object o)
+ // {
+ // }
+
+ // TODO12:
+ // public void add(int index, Object element)
+ // {
+ // }
+
+ // TODO12:
+ // public boolean addAll(Collection c)
+ // {
+ // }
+
+ // TODO12:
+ // public boolean addAll(int index, Collection c)
+ // {
+ // }
+
+ // TODO12:
+ // public void clear()
+ // {
+ // }
+
+ // TODO12:
+ // public boolean containsAll(Collection c)
+ // {
+ // }
+
+ // TODO12:
+ // public boolean equals(Object o)
+ // {
+ // }
+
+ // TODO12:
+ // public int hashCode()
+ // {
+ // }
+
+ // TODO12:
+ // public Object get(int index)
+ // {
+ // }
+
+ // TODO12:
+ // public boolean remove(Object o)
+ // {
+ // }
+
+ // TODO12:
+ // public Object remove(int index)
+ // {
+ // }
+
+ // TODO12:
+ // public boolean removeAll(Collection c)
+ // {
+ // }
+
+ // TODO12:
+ // public boolean retainAll(Collection c)
+ // {
+ // }
+
+ // TODO12:
+ // public Object set(int index, Object element)
+ // {
+ // }
+
+ // TODO12:
+ // public Object[] toArray()
+ // {
+ // }
+
+ // TODO12:
+ // public Object[] toArray(Object[] a)
+ // {
+ // }
+}
diff --git a/libjava/java/util/natDate.cc b/libjava/java/util/natDate.cc
new file mode 100644
index 0000000..27f91f6
--- /dev/null
+++ b/libjava/java/util/natDate.cc
@@ -0,0 +1,45 @@
+/* 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. */
+
+#include <config.h>
+
+// We want to make sure to pick up the POSIX ctime_r. Some systems,
+// such as Solaris 2.6, have their own version as well.
+#ifdef HAVE_CTIME_R
+#define _POSIX_PTHREAD_SEMANTICS
+#endif
+
+#include <cni.h>
+#include <java/util/Date.h>
+#include <java/lang/String.h>
+
+#include <time.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+jstring
+java::util::Date::toString()
+{
+#ifdef HAVE_CTIME_R
+ time_t t = millis / 1000;
+ char buf[30];
+ return JvNewStringLatin1 (ctime_r (&t, buf));
+#elif defined (HAVE_CTIME)
+ // FIXME: this isn't thread-safe.
+ time_t t = millis / 1000;
+ return JvNewStringLatin1 (ctime (&t));
+#else
+ return NULL;
+#endif
+}
diff --git a/libjava/java/util/natGregorianCalendar.cc b/libjava/java/util/natGregorianCalendar.cc
new file mode 100644
index 0000000..cfa98bd
--- /dev/null
+++ b/libjava/java/util/natGregorianCalendar.cc
@@ -0,0 +1,124 @@
+/* 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. */
+
+#include <config.h>
+
+// We want to make sure to pick up the POSIX `_r' functions. Some
+// systems, such as Solaris 2.6, require this define in order to
+// declare the functions in the appropriate header.
+#if defined (HAVE_GMTIME_R) || defined (HAVE_LOCALTIME_R)
+# define _POSIX_PTHREAD_SEMANTICS
+# ifndef _REENTRANT
+# define _REENTRANT
+# endif /* _REENTRANT */
+#endif
+
+#ifdef ECOS
+#include <string.h>
+#endif
+
+#include <cni.h>
+#include <java/util/TimeZone.h>
+#include <java/util/GregorianCalendar.h>
+#include <time.h>
+
+void
+java::util::GregorianCalendar::computeTime ()
+{
+ struct tm tim;
+ tim.tm_sec = elements(fields)[SECOND];
+ tim.tm_min = elements(fields)[MINUTE];
+ tim.tm_hour = elements(fields)[HOUR_OF_DAY];
+ tim.tm_mday = elements(fields)[DATE];
+ tim.tm_mon = elements(fields)[MONTH];
+ tim.tm_year = elements(fields)[YEAR] - 1900;
+ tim.tm_isdst = 0; // FIXME
+#ifndef ECOS
+ // FIXME: None of the standard C library access to the ECOS calendar
+ // is yet available.
+ time_t t = mktime (&tim);
+#else
+ time_t t = 0;
+#endif
+
+ // Adjust for local timezone (introduced by mktime) and our
+ // timezone.
+#if defined (STRUCT_TM_HAS_GMTOFF)
+ t += tim.tm_gmtoff;
+#elif defined (HAVE_TIMEZONE)
+ t -= timezone;
+#endif
+ java::util::TimeZone *zone = getTimeZone ();
+ t += zone->getRawOffset();
+
+ // Adjust for milliseconds.
+ time = t * 1000 + elements(fields)[MILLISECOND];
+
+ isTimeSet = true;
+}
+
+void
+java::util::GregorianCalendar::computeFields ()
+{
+ time_t t = time / 1000;
+ int millis = time % 1000;
+ if (t < 0 && millis != 0)
+ {
+ t--;
+ millis = t - 1000 * t;
+ }
+ elements(fields)[MILLISECOND] = millis;
+ struct tm tim;
+ java::util::TimeZone *zone = getTimeZone ();
+
+ // FIXME: None of the standard C library access to the ECOS calendar
+ // is yet available.
+#ifdef ECOS
+ memset (&tim, 0, sizeof tim);
+#else
+ if (zone->getRawOffset() == 0 || ! zone->useDaylightTime())
+ {
+#if defined(__JV_POSIX_THREADS__) && defined(HAVE_GMTIME_R)
+ gmtime_r (&t, &tim);
+#else
+ // Get global lock (because gmtime uses a global buffer). FIXME
+ tim = *(struct tm*) gmtime (&t);
+ // Release global lock. FIXME
+#endif
+ }
+ else
+ {
+#if defined(__JV_POSIX_THREADS__) && defined(HAVE_LOCALTIME_R)
+ localtime_r (&t, &tim);
+#else
+ // Get global lock (because localtime uses a global buffer). FIXME
+ tim = *(struct tm*) localtime (&t);
+ // Release global lock. FIXME
+#endif
+ }
+#endif /* ECOS */
+ elements(fields)[SECOND] = tim.tm_sec;
+ elements(fields)[MINUTE] = tim.tm_min;
+ elements(fields)[HOUR_OF_DAY] = tim.tm_hour;
+ elements(fields)[AM_PM] = tim.tm_hour < 12 ? AM : PM;
+ elements(fields)[HOUR] = tim.tm_hour % 12;
+ elements(fields)[DATE] = tim.tm_mday;
+ elements(fields)[MONTH] = tim.tm_mon;
+ elements(fields)[YEAR] = 1900 + tim.tm_year;
+ elements(fields)[DAY_OF_WEEK] = tim.tm_wday + 1;
+ elements(fields)[DAY_OF_WEEK_IN_MONTH] = ((tim.tm_mday - 1) / 7) + 1;
+ elements(fields)[DAY_OF_YEAR] = tim.tm_yday + 1;
+ elements(fields)[WEEK_OF_MONTH]
+ = (tim.tm_mday + 6 + (5 - tim.tm_wday + getFirstDayOfWeek()) % 7) / 7;
+ elements(fields)[WEEK_OF_YEAR]
+ = (tim.tm_yday + 7 + (5 - tim.tm_wday + getFirstDayOfWeek()) % 7) / 7;
+ elements(fields)[ERA] = AD;
+ elements(fields)[DST_OFFSET] = tim.tm_isdst <= 0 ? 0 : 60*60*1000;
+ elements(fields)[ZONE_OFFSET] = getTimeZone()->getRawOffset();
+ areFieldsSet = true;
+}
diff --git a/libjava/java/util/zip/Adler32.java b/libjava/java/util/zip/Adler32.java
new file mode 100644
index 0000000..8e4ab9a
--- /dev/null
+++ b/libjava/java/util/zip/Adler32.java
@@ -0,0 +1,101 @@
+/* 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.util.zip;
+
+/**
+ * @author Per Bothner
+ * @date April 6, 1999.
+ */
+
+/*
+ * Written using on-line Java Platform 1.2 API Specification, as well
+ * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
+ * The actual Adler32 algorithm is taken from RFC 1950.
+ * Status: Believed complete and correct.
+ */
+
+public class Adler32 implements Checksum
+{
+ private static int BASE = 65521; /* largest prime smaller than 65536 */
+
+ int s1;
+ int s2;
+
+ public Adler32 ()
+ {
+ reset();
+ }
+
+ public void reset () { s1 = 1; s2 = 0; }
+
+ public void update (int bval)
+ {
+ s1 = (s1 + (bval & 0xFF)) % BASE;
+ s2 = (s1 + s2) % BASE;
+ }
+
+ public void update (byte[] buffer)
+ {
+ update(buffer, 0, buffer.length);
+ }
+
+ public void update (byte[] buf, int off, int len)
+ {
+ int s1 = this.s1;
+ int s2 = this.s2;
+ while (len > 0)
+ {
+ // We can defer the modulo operation.
+ int n = 4000;
+ if (n > len)
+ n = len;
+ len -= n;
+ while (--n >= 0)
+ {
+ s1 = s1 + (buf[off++] & 0xFF);
+ s2 = s2 + s1;
+ }
+ s1 %= BASE;
+ s2 %= BASE;
+ }
+ this.s1 = s1;
+ this.s2 = s2;
+ }
+
+ public long getValue()
+ {
+ return ((long) s2 << 16) + s1;
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libjava/java/util/zip/CRC32.java b/libjava/java/util/zip/CRC32.java
new file mode 100644
index 0000000..ab19b58
--- /dev/null
+++ b/libjava/java/util/zip/CRC32.java
@@ -0,0 +1,70 @@
+/* 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.util.zip;
+
+/**
+ * @author Per Bothner
+ * @date April 1, 1999.
+ */
+
+/*
+ * Written using on-line Java Platform 1.2 API Specification, as well
+ * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
+ * The actual CRC32 algorithm is taken from RFC 1952.
+ * Status: Believed complete and correct.
+ */
+
+public class CRC32 implements Checksum
+{
+ int crc = 0;
+
+ static int[] crc_table = make_crc_table();
+
+ /* Make the table for a fast CRC. */
+ static int[] make_crc_table ()
+ {
+ int[] crc_table = new int[256];
+ for (int n = 0; n < 256; n++)
+ {
+ int c = n;
+ for (int k = 8; --k >= 0; )
+ {
+ if ((c & 1) != 0)
+ c = 0xedb88320 ^ (c >>> 1);
+ else
+ c = c >>> 1;
+ }
+ crc_table[n] = c;
+ }
+ return crc_table;
+ }
+
+ public long getValue ()
+ {
+ return (long) crc & 0xffffffffL;
+ }
+
+ public void reset () { crc = 0; }
+
+ public void update (int bval)
+ {
+ int c = ~crc;
+ c = crc_table[(c ^ bval) & 0xff] ^ (c >>> 8);
+ crc = ~c;
+ }
+
+ public void update (byte[] buf, int off, int len)
+ {
+ int c = ~crc;
+ while (--len >= 0)
+ c = crc_table[(c ^ buf[off++]) & 0xff] ^ (c >>> 8);
+ crc = ~c;
+ }
+ public void update (byte[] buf) { update(buf, 0, buf.length); }
+}
diff --git a/libjava/java/util/zip/Checksum.java b/libjava/java/util/zip/Checksum.java
new file mode 100644
index 0000000..85cdae2
--- /dev/null
+++ b/libjava/java/util/zip/Checksum.java
@@ -0,0 +1,31 @@
+/* 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.util.zip;
+
+/**
+ * @author Per Bothner
+ * @date January 9, 1999.
+ */
+
+/*
+ * Written using on-line Java Platform 1.2 API Specification, as well
+ * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
+ * Status: Believed complete and correct.
+ */
+
+public interface Checksum
+{
+ public long getValue ();
+
+ public void reset ();
+
+ public void update (int bval);
+
+ public void update (byte[] buf, int off, int len);
+}
diff --git a/libjava/java/util/zip/Deflater.java b/libjava/java/util/zip/Deflater.java
new file mode 100644
index 0000000..81312e2
--- /dev/null
+++ b/libjava/java/util/zip/Deflater.java
@@ -0,0 +1,13 @@
+/* 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.util.zip;
+
+public class Deflater
+{
+}
diff --git a/libjava/java/util/zip/DeflaterOutputStream.java b/libjava/java/util/zip/DeflaterOutputStream.java
new file mode 100644
index 0000000..4f0b8b4
--- /dev/null
+++ b/libjava/java/util/zip/DeflaterOutputStream.java
@@ -0,0 +1,46 @@
+/* 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.util.zip;
+import java.io.*;
+
+/** JUST AN INCOMPLETE STUB! */
+
+public class DeflaterOutputStream extends FilterOutputStream
+{
+ protected byte[] buf;
+
+ protected Deflater def;
+
+ public DeflaterOutputStream(OutputStream out)
+ {
+ this(out, null, 512);
+ }
+
+ public DeflaterOutputStream(OutputStream out, Deflater defl)
+ {
+ this(out, defl, 512);
+ }
+
+ public DeflaterOutputStream(OutputStream out, Deflater defl, int bufsize)
+ {
+ super(out);
+ buf = new byte[bufsize];
+ def = defl;
+ }
+
+ public void finish () throws IOException
+ {
+ }
+
+ public void close () throws IOException
+ {
+ finish();
+ out.close();
+ }
+}
diff --git a/libjava/java/util/zip/ZipConstants.java b/libjava/java/util/zip/ZipConstants.java
new file mode 100644
index 0000000..4aec92e
--- /dev/null
+++ b/libjava/java/util/zip/ZipConstants.java
@@ -0,0 +1,13 @@
+/* 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.util.zip;
+
+public interface ZipConstants
+{
+}
diff --git a/libjava/java/util/zip/ZipEntry.java b/libjava/java/util/zip/ZipEntry.java
new file mode 100644
index 0000000..d472de5
--- /dev/null
+++ b/libjava/java/util/zip/ZipEntry.java
@@ -0,0 +1,84 @@
+/* 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.util.zip;
+
+/**
+ * @author Per Bothner
+ * @date January 6, 1999.
+ */
+
+/*
+ * Written using on-line Java Platform 1.2 API Specification, as well
+ * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
+ * Status: Believed complete and correct.
+ */
+
+public class ZipEntry
+{
+ // These values were determined using a simple test program.
+ public static final int STORED = 0;
+ public static final int DEFLATED = 8;
+
+ String comment;
+ long compressedSize = -1;
+ long crc = -1;
+ byte[] extra;
+ int method = -1;
+ String name;
+ long size = -1;
+ long time = -1;
+
+ ZipEntry next;
+
+ public ZipEntry (String name)
+ {
+ this.name = name;
+ }
+
+ public String getComment () { return comment; }
+
+ public long getCompressedSize () { return compressedSize; }
+
+ public long getCrc () { return crc; }
+
+ public byte[] getExtra() { return extra; }
+
+ public int getMethod () { return method; }
+
+ public String getName () { return name; }
+
+ public long getSize () { return size; }
+
+ public long getTime () { return time; }
+
+ public boolean isDirectory ()
+ {
+ if (name != null)
+ {
+ int nlen = name.length();
+ if (nlen > 0 && name.charAt(nlen-1) == '/')
+ return true;
+ }
+ return false;
+ }
+
+ public void setComment (String comment) { this.comment = comment; }
+
+ public void setCrc (long crc) { this.crc = crc; }
+
+ public void setExtra (byte[] extra) { this.extra = extra; }
+
+ public void setMethod(int method) { this.method = method; }
+
+ public void setSize (long size) { this.size = size; }
+
+ public void setTime (long time) { this.time = time; }
+
+ public String toString () { return name; }
+}
diff --git a/libjava/java/util/zip/ZipException.java b/libjava/java/util/zip/ZipException.java
new file mode 100644
index 0000000..5c038a5
--- /dev/null
+++ b/libjava/java/util/zip/ZipException.java
@@ -0,0 +1,33 @@
+// ZipException.java
+
+/* Copyright (C) 1998, 1999 Cygnus Solutions
+
+ This file is part of libjava.
+
+This software is copyrighted work licensed under the terms of the
+Libjava License. Please consult the file "LIBJAVA_LICENSE" for
+details. */
+
+package java.util.zip;
+
+/**
+ * @author Per Bothner
+ * @date January 9, 1999.
+ */
+
+/* Written using on-line Java Platform 1.2 API Specification.
+ * Believed complete and correct.
+ */
+
+public class ZipException extends java.io.IOException
+{
+ public ZipException ()
+ {
+ super();
+ }
+
+ public ZipException (String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/libjava/java/util/zip/ZipFile.java b/libjava/java/util/zip/ZipFile.java
new file mode 100644
index 0000000..75f0a3d
--- /dev/null
+++ b/libjava/java/util/zip/ZipFile.java
@@ -0,0 +1,81 @@
+/* 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.util.zip;
+import java.io.*;
+
+/** JUST AN INCOMPLETE STUB! */
+
+public class ZipFile implements ZipConstants
+{
+
+ String name;
+ ZipEntry entries;
+
+ public ZipFile (String fname) throws IOException
+ {
+ name = fname;
+ // FIXME
+ }
+
+ public ZipFile (File f) throws IOException
+ {
+ this(f.getPath());
+ }
+
+ public java.util.Enumeration entries()
+ {
+ return new ZipEnumeration(this);
+ }
+
+ public void close() throws IOException
+ {
+ // FIXME
+ }
+
+ public ZipEntry getEntry(String name)
+ {
+ for (ZipEntry entry = entries; entry != null; entry = entry.next)
+ {
+ if (name.equals(entry.getName()))
+ return entry;
+ }
+ return null;
+ }
+
+ public InputStream getInputStream(ZipEntry ze) throws IOException
+ {
+ return null; // FIXME
+ }
+
+ public String getName () { return name; }
+}
+
+class ZipEnumeration implements java.util.Enumeration
+{
+ ZipEntry entry;
+
+ ZipEnumeration (ZipFile zfile)
+ {
+ entry = zfile.entries;
+ }
+
+ public boolean hasMoreElements ()
+ {
+ return entry != null;
+ }
+
+ public Object nextElement ()
+ {
+ ZipEntry cur = entry;
+ if (cur == null)
+ throw new java.util.NoSuchElementException();
+ entry = cur.next;
+ return cur;
+ }
+}
diff --git a/libjava/java/util/zip/ZipOutputStream.java b/libjava/java/util/zip/ZipOutputStream.java
new file mode 100644
index 0000000..42cfb00
--- /dev/null
+++ b/libjava/java/util/zip/ZipOutputStream.java
@@ -0,0 +1,26 @@
+/* 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.util.zip;
+import java.io.*;
+
+/** JUST AN INCOMPLETE STUB! */
+
+public class ZipOutputStream extends DeflaterOutputStream
+ implements ZipConstants
+{
+ public ZipOutputStream (OutputStream out)
+ {
+ super(out);
+ }
+
+ public void putNextEntry (ZipEntry entry) throws IOException
+ {
+ throw new Error ("java.util.zip.ZipOutputStream.putNextEntry: not implemented");
+ }
+}