diff options
author | Tom Tromey <tromey@gcc.gnu.org> | 1999-04-07 14:42:40 +0000 |
---|---|---|
committer | Tom Tromey <tromey@gcc.gnu.org> | 1999-04-07 14:42:40 +0000 |
commit | ee9dd3721be68b9fa63dea9aa5a1d86e66958cde (patch) | |
tree | d96801a16fdf03a5682ef98730fe333a46eef944 /libjava/java/util | |
parent | 140fa895c6b859f827fc4437b91775a82cd105fb (diff) | |
download | gcc-ee9dd3721be68b9fa63dea9aa5a1d86e66958cde.zip gcc-ee9dd3721be68b9fa63dea9aa5a1d86e66958cde.tar.gz gcc-ee9dd3721be68b9fa63dea9aa5a1d86e66958cde.tar.bz2 |
Initial revision
From-SVN: r26263
Diffstat (limited to 'libjava/java/util')
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"); + } +} |